add helper methods for accessing struct tail
This commit is contained in:
parent
e3de14e463
commit
7aa5f39d3b
9 changed files with 31 additions and 34 deletions
|
@ -981,7 +981,7 @@ fn check_type_defn<'tcx>(tcx: TyCtxt<'tcx>, item: &hir::Item<'tcx>, all_sized: b
|
||||||
// intermediate types must be sized.
|
// intermediate types must be sized.
|
||||||
let needs_drop_copy = || {
|
let needs_drop_copy = || {
|
||||||
packed && {
|
packed && {
|
||||||
let ty = tcx.type_of(variant.fields.raw.last().unwrap().did).subst_identity();
|
let ty = tcx.type_of(variant.tail().did).subst_identity();
|
||||||
let ty = tcx.erase_regions(ty);
|
let ty = tcx.erase_regions(ty);
|
||||||
if ty.has_infer() {
|
if ty.has_infer() {
|
||||||
tcx.sess
|
tcx.sess
|
||||||
|
|
|
@ -103,15 +103,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
Ok(match *t.kind() {
|
Ok(match *t.kind() {
|
||||||
ty::Slice(_) | ty::Str => Some(PointerKind::Length),
|
ty::Slice(_) | ty::Str => Some(PointerKind::Length),
|
||||||
ty::Dynamic(ref tty, _, ty::Dyn) => Some(PointerKind::VTable(tty.principal_def_id())),
|
ty::Dynamic(ref tty, _, ty::Dyn) => Some(PointerKind::VTable(tty.principal_def_id())),
|
||||||
ty::Adt(def, substs) if def.is_struct() => {
|
ty::Adt(def, substs) if def.is_struct() => match def.non_enum_variant().tail_opt() {
|
||||||
match def.non_enum_variant().fields.raw.last() {
|
|
||||||
None => Some(PointerKind::Thin),
|
None => Some(PointerKind::Thin),
|
||||||
Some(f) => {
|
Some(f) => {
|
||||||
let field_ty = self.field_ty(span, f, substs);
|
let field_ty = self.field_ty(span, f, substs);
|
||||||
self.pointer_kind(field_ty, span)?
|
self.pointer_kind(field_ty, span)?
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
|
||||||
ty::Tuple(fields) => match fields.last() {
|
ty::Tuple(fields) => match fields.last() {
|
||||||
None => Some(PointerKind::Thin),
|
None => Some(PointerKind::Thin),
|
||||||
Some(&f) => self.pointer_kind(f, span)?,
|
Some(&f) => self.pointer_kind(f, span)?,
|
||||||
|
|
|
@ -2028,6 +2028,22 @@ impl VariantDef {
|
||||||
|
|
||||||
&self.fields[FieldIdx::from_u32(0)]
|
&self.fields[FieldIdx::from_u32(0)]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the last field in this variant, if present.
|
||||||
|
#[inline]
|
||||||
|
pub fn tail_opt(&self) -> Option<&FieldDef> {
|
||||||
|
self.fields.raw.last()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the last field in this variant.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// Panics, if the variant has no fields.
|
||||||
|
#[inline]
|
||||||
|
pub fn tail(&self) -> &FieldDef {
|
||||||
|
self.tail_opt().expect("expected unsized ADT to have a tail field")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for VariantDef {
|
impl PartialEq for VariantDef {
|
||||||
|
|
|
@ -230,7 +230,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||||
if !def.is_struct() {
|
if !def.is_struct() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
match def.non_enum_variant().fields.raw.last() {
|
match def.non_enum_variant().tail_opt() {
|
||||||
Some(field) => {
|
Some(field) => {
|
||||||
f();
|
f();
|
||||||
ty = field.ty(self, substs);
|
ty = field.ty(self, substs);
|
||||||
|
@ -304,7 +304,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||||
(&ty::Adt(a_def, a_substs), &ty::Adt(b_def, b_substs))
|
(&ty::Adt(a_def, a_substs), &ty::Adt(b_def, b_substs))
|
||||||
if a_def == b_def && a_def.is_struct() =>
|
if a_def == b_def && a_def.is_struct() =>
|
||||||
{
|
{
|
||||||
if let Some(f) = a_def.non_enum_variant().fields.raw.last() {
|
if let Some(f) = a_def.non_enum_variant().tail_opt() {
|
||||||
a = f.ty(self, a_substs);
|
a = f.ty(self, a_substs);
|
||||||
b = f.ty(self, b_substs);
|
b = f.ty(self, b_substs);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -366,7 +366,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::Adt(def, substs) if def.is_struct() => {
|
ty::Adt(def, substs) if def.is_struct() => {
|
||||||
match def.non_enum_variant().fields.raw.last() {
|
match def.non_enum_variant().tail_opt() {
|
||||||
None => tcx.types.unit,
|
None => tcx.types.unit,
|
||||||
Some(field_def) => {
|
Some(field_def) => {
|
||||||
let self_ty = field_def.ty(tcx, substs);
|
let self_ty = field_def.ty(tcx, substs);
|
||||||
|
|
|
@ -398,12 +398,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||||
return Err(NoSolution);
|
return Err(NoSolution);
|
||||||
}
|
}
|
||||||
|
|
||||||
let tail_field = a_def
|
let tail_field = a_def.non_enum_variant().tail();
|
||||||
.non_enum_variant()
|
|
||||||
.fields
|
|
||||||
.raw
|
|
||||||
.last()
|
|
||||||
.expect("expected unsized ADT to have a tail field");
|
|
||||||
let tail_field_ty = tcx.type_of(tail_field.did);
|
let tail_field_ty = tcx.type_of(tail_field.did);
|
||||||
|
|
||||||
let a_tail_ty = tail_field_ty.subst(tcx, a_substs);
|
let a_tail_ty = tail_field_ty.subst(tcx, a_substs);
|
||||||
|
|
|
@ -1125,12 +1125,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
return Err(Unimplemented);
|
return Err(Unimplemented);
|
||||||
}
|
}
|
||||||
|
|
||||||
let tail_field = def
|
let tail_field = def.non_enum_variant().tail();
|
||||||
.non_enum_variant()
|
|
||||||
.fields
|
|
||||||
.raw
|
|
||||||
.last()
|
|
||||||
.expect("expected unsized ADT to have a tail field");
|
|
||||||
let tail_field_ty = tcx.type_of(tail_field.did);
|
let tail_field_ty = tcx.type_of(tail_field.did);
|
||||||
|
|
||||||
// Extract `TailField<T>` and `TailField<U>` from `Struct<T>` and `Struct<U>`,
|
// Extract `TailField<T>` and `TailField<U>` from `Struct<T>` and `Struct<U>`,
|
||||||
|
|
|
@ -480,7 +480,7 @@ fn layout_of_uncached<'tcx>(
|
||||||
.any(|(i, v)| v.discr != ty::VariantDiscr::Relative(i.as_u32()));
|
.any(|(i, v)| v.discr != ty::VariantDiscr::Relative(i.as_u32()));
|
||||||
|
|
||||||
let maybe_unsized = def.is_struct()
|
let maybe_unsized = def.is_struct()
|
||||||
&& def.non_enum_variant().fields.raw.last().is_some_and(|last_field| {
|
&& def.non_enum_variant().tail_opt().is_some_and(|last_field| {
|
||||||
let param_env = tcx.param_env(def.did());
|
let param_env = tcx.param_env(def.did());
|
||||||
!tcx.type_of(last_field.did).subst_identity().is_sized(tcx, param_env)
|
!tcx.type_of(last_field.did).subst_identity().is_sized(tcx, param_env)
|
||||||
});
|
});
|
||||||
|
@ -502,14 +502,7 @@ fn layout_of_uncached<'tcx>(
|
||||||
// If the struct tail is sized and can be unsized, check that unsizing doesn't move the fields around.
|
// If the struct tail is sized and can be unsized, check that unsizing doesn't move the fields around.
|
||||||
if cfg!(debug_assertions)
|
if cfg!(debug_assertions)
|
||||||
&& maybe_unsized
|
&& maybe_unsized
|
||||||
&& def
|
&& def.non_enum_variant().tail().ty(tcx, substs).is_sized(tcx, cx.param_env)
|
||||||
.non_enum_variant()
|
|
||||||
.fields
|
|
||||||
.raw
|
|
||||||
.last()
|
|
||||||
.unwrap()
|
|
||||||
.ty(tcx, substs)
|
|
||||||
.is_sized(tcx, cx.param_env)
|
|
||||||
{
|
{
|
||||||
let mut variants = variants;
|
let mut variants = variants;
|
||||||
let tail_replacement = cx.layout_of(Ty::new_slice(tcx, tcx.types.u8)).unwrap();
|
let tail_replacement = cx.layout_of(Ty::new_slice(tcx, tcx.types.u8)).unwrap();
|
||||||
|
|
|
@ -103,7 +103,7 @@ fn adt_sized_constraint(tcx: TyCtxt<'_>, def_id: DefId) -> &[Ty<'_>] {
|
||||||
let result = tcx.mk_type_list_from_iter(
|
let result = tcx.mk_type_list_from_iter(
|
||||||
def.variants()
|
def.variants()
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|v| v.fields.raw.last())
|
.filter_map(|v| v.tail_opt())
|
||||||
.flat_map(|f| sized_constraint_for_ty(tcx, def, tcx.type_of(f.did).subst_identity())),
|
.flat_map(|f| sized_constraint_for_ty(tcx, def, tcx.type_of(f.did).subst_identity())),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue