use alloc::vec::Vec;
use core::range::{RangeFrom, RangeToInclusive};
use crate::rustc_abi as abi;
use crate::rustc_abi::Integer::{I8, I32};
use crate::rustc_abi::Primitive::{self, Float, Int, Pointer};
use crate::rustc_abi::{
AddressSpace, BackendRepr, FIRST_VARIANT, FieldIdx, FieldsShape, HasDataLayout, Layout,
LayoutCalculatorError, LayoutData, Niche, ReprOptions, Scalar, Size, StructKind, VariantIdx,
WrappingRange,
};
use crate::rustc_hashes::Hash64;
use crate::find_attr;
use crate::rustc_index::{Idx as _, IndexVec};
use crate::bug;
use crate::rustc_middle::query::Providers;
use crate::rustc_middle::traits::ObligationCause;
use crate::rustc_middle::ty::layout::{
FloatExt, HasTyCtxt, IntegerExt, LayoutCx, LayoutError, LayoutOf, SimdLayoutError, TyAndLayout,
};
use crate::rustc_middle::ty::{
self, EarlyBinder, PseudoCanonicalInput, Ty, TyCtxt, TypeVisitableExt, Unnormalized,
};
use crate::rustc_structures::Limit;
use tracing::{debug, instrument};
use crate::rustc_ty_utils::diagnostics::NonPrimitiveSimdType;
mod invariant;
pub(crate) fn provide(providers: &mut Providers) {
*providers = Providers { layout_of, ..*providers };
}
#[instrument(skip(tcx, query), level = "debug")]
fn layout_of<'tcx>(
tcx: TyCtxt<'tcx>,
query: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>,
) -> Result<TyAndLayout<'tcx>, &'tcx LayoutError<'tcx>> {
let PseudoCanonicalInput { typing_env: original_typing_env, value: original_ty } = query;
debug!(?original_ty);
let typing_env = original_typing_env.with_post_analysis_normalized(tcx);
let unnormalized_ty = if typing_env != original_typing_env {
ty::set_aliases_to_non_rigid(tcx, original_ty)
} else {
ty::Unnormalized::new_wip(original_ty)
};
let normalized_ty = match tcx.try_normalize_erasing_regions(typing_env, unnormalized_ty) {
Ok(t) => t,
Err(normalization_error) => {
return Err(tcx.arena.alloc(LayoutError::NormalizationFailure(
unnormalized_ty.skip_normalization(),
normalization_error,
)));
}
};
if normalized_ty != original_ty {
return tcx.layout_of(typing_env.as_query_input(normalized_ty));
}
match typing_env.typing_mode() {
ty::TypingMode::Codegen => {
let with_postanalysis =
ty::TypingEnv::new(typing_env.param_env, ty::TypingMode::PostAnalysis);
let res = tcx.layout_of(with_postanalysis.as_query_input(normalized_ty));
match res {
Err(LayoutError::TooGeneric(_)) => {}
_ => return res,
};
}
ty::TypingMode::Coherence
| ty::TypingMode::Typeck { .. }
| ty::TypingMode::PostTypeckUntilBorrowck { .. }
| ty::TypingMode::PostBorrowck { .. }
| ty::TypingMode::Reflection
| ty::TypingMode::ErasedNotCoherence(_)
| ty::TypingMode::PostAnalysis => {}
}
let cx = LayoutCx::new(tcx, typing_env);
let layout = layout_of_uncached(&cx, normalized_ty)?;
let layout = TyAndLayout { ty: normalized_ty, layout };
invariant::layout_sanity_check(&cx, &layout);
Ok(layout)
}
fn error<'tcx>(cx: &LayoutCx<'tcx>, err: LayoutError<'tcx>) -> &'tcx LayoutError<'tcx> {
cx.tcx().arena.alloc(err)
}
fn map_error<'tcx>(
cx: &LayoutCx<'tcx>,
ty: Ty<'tcx>,
err: LayoutCalculatorError<TyAndLayout<'tcx>>,
) -> &'tcx LayoutError<'tcx> {
let err = match err {
LayoutCalculatorError::SizeOverflow => {
LayoutError::SizeOverflow(ty)
}
LayoutCalculatorError::UnexpectedUnsized(field) => {
assert!(field.layout.is_unsized(), "invalid layout error {err:#?}");
if cx.typing_env.param_env.is_empty() {
cx.tcx().dcx().delayed_bug(format!(
"encountered unexpected unsized field in layout of {ty:?}: {field:#?}"
));
}
LayoutError::Unknown(ty)
}
LayoutCalculatorError::EmptyUnion => {
let guar =
cx.tcx().dcx().delayed_bug(format!("computed layout of empty union: {ty:?}"));
LayoutError::ReferencesError(guar)
}
LayoutCalculatorError::ReprConflict => {
let guar = cx
.tcx()
.dcx()
.delayed_bug(format!("computed impossible repr (packed enum?): {ty:?}"));
LayoutError::ReferencesError(guar)
}
LayoutCalculatorError::ZeroLengthSimdType => {
LayoutError::InvalidSimd { ty, kind: SimdLayoutError::ZeroLength }
}
LayoutCalculatorError::OversizedSimdType { max_lanes } => {
LayoutError::InvalidSimd { ty, kind: SimdLayoutError::TooManyLanes(Limit(max_lanes)) }
}
LayoutCalculatorError::NonPrimitiveSimdType(field) => {
cx.tcx().dcx().emit_fatal(NonPrimitiveSimdType { ty, e_ty: field.ty })
}
};
error(cx, err)
}
fn extract_const_value<'tcx>(
cx: &LayoutCx<'tcx>,
ty: Ty<'tcx>,
ct: ty::Const<'tcx>,
) -> Result<ty::Value<'tcx>, &'tcx LayoutError<'tcx>> {
match ct.kind() {
ty::ConstKind::Value(cv) => Ok(cv),
ty::ConstKind::Param(_) | ty::ConstKind::Expr(_) => {
if !ct.has_param() {
bug!("failed to normalize const, but it is not generic: {ct:?}");
}
Err(error(cx, LayoutError::TooGeneric(ty)))
}
ty::ConstKind::Alias(_, _) => {
let err = if ct.has_param() {
LayoutError::TooGeneric(ty)
} else {
LayoutError::Unknown(ty)
};
Err(error(cx, err))
}
ty::ConstKind::Infer(_)
| ty::ConstKind::Bound(..)
| ty::ConstKind::Placeholder(_)
| ty::ConstKind::Error(_) => {
bug!("layout_of: unexpected const: {ct:?}");
}
}
}
fn layout_of_uncached<'tcx>(
cx: &LayoutCx<'tcx>,
ty: Ty<'tcx>,
) -> Result<Layout<'tcx>, &'tcx LayoutError<'tcx>> {
if let Err(guar) = ty.error_reported() {
return Err(error(cx, LayoutError::ReferencesError(guar)));
}
let tcx = cx.tcx();
let dl = cx.data_layout();
let map_layout = |result: Result<_, _>| match result {
Ok(layout) => Ok(tcx.mk_layout(layout)),
Err(err) => Err(map_error(cx, ty, err)),
};
let scalar_unit = |value: Primitive| {
let size = value.size(dl);
assert!(size.bits() <= 128);
Scalar::Initialized { value, valid_range: WrappingRange::full(size) }
};
let scalar = |value: Primitive| tcx.mk_layout(LayoutData::scalar(cx, scalar_unit(value)));
let univariant = |tys: &[Ty<'tcx>], kind| {
let fields =
tys.iter().map(|ty| cx.layout_of(*ty)).collect::<Result<IndexVec<_, _>, _>>()?;
let repr = ReprOptions::default();
map_layout(cx.calc.univariant(&fields, &repr, kind))
};
debug_assert!(!ty.has_non_region_infer());
Ok(match *ty.kind() {
ty::Pat(ty, pat) => {
let layout = cx.layout_of(ty)?.layout;
let mut layout = LayoutData::clone(&layout.0);
match *pat {
ty::PatternKind::Range { start, end } => {
if let BackendRepr::Scalar(scalar) = &mut layout.backend_repr {
scalar.valid_range_mut().start = extract_const_value(cx, ty, start)?
.try_to_bits(tcx, cx.typing_env)
.ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?;
scalar.valid_range_mut().end = extract_const_value(cx, ty, end)?
.try_to_bits(tcx, cx.typing_env)
.ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?;
if scalar.is_signed() {
let range = scalar.valid_range_mut();
let start = layout.size.sign_extend(range.start);
let end = layout.size.sign_extend(range.end);
if end < start {
let guar = tcx.dcx().err(format!(
"pattern type ranges cannot wrap: {start}..={end}"
));
return Err(error(cx, LayoutError::ReferencesError(guar)));
}
} else {
let range = scalar.valid_range_mut();
if range.end < range.start {
let guar = tcx.dcx().err(format!(
"pattern type ranges cannot wrap: {}..={}",
range.start, range.end
));
return Err(error(cx, LayoutError::ReferencesError(guar)));
}
};
let niche = Niche {
offset: Size::ZERO,
value: scalar.primitive(),
valid_range: scalar.valid_range(cx),
};
layout.largest_niche = Some(niche);
} else {
bug!("pattern type with range but not scalar layout: {ty:?}, {layout:?}")
}
}
ty::PatternKind::NotNull => {
if let BackendRepr::Scalar(scalar)
| BackendRepr::ScalarPair { a: scalar, b: _, b_offset: _ } =
&mut layout.backend_repr
{
scalar.valid_range_mut().start = 1;
let niche = Niche {
offset: Size::ZERO,
value: scalar.primitive(),
valid_range: scalar.valid_range(cx),
};
layout.largest_niche = Some(niche);
} else {
bug!(
"pattern type with `!null` pattern but not scalar/pair layout: {ty:?}, {layout:?}"
)
}
}
ty::PatternKind::Or(variants) => match *variants[0] {
ty::PatternKind::Range { .. } => {
if let BackendRepr::Scalar(scalar) = &mut layout.backend_repr {
let variants: Result<Vec<_>, _> = variants
.iter()
.map(|pat| match *pat {
ty::PatternKind::Range { start, end } => Ok((
extract_const_value(cx, ty, start)
.unwrap()
.try_to_bits(tcx, cx.typing_env)
.ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?,
extract_const_value(cx, ty, end)
.unwrap()
.try_to_bits(tcx, cx.typing_env)
.ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?,
)),
ty::PatternKind::NotNull | ty::PatternKind::Or(_) => {
unreachable!("mixed or patterns are not allowed")
}
})
.collect();
let mut variants = variants?;
if !scalar.is_signed() {
let guar = tcx.dcx().err(format!(
"only signed integer base types are allowed for or-pattern pattern types at present"
));
return Err(error(cx, LayoutError::ReferencesError(guar)));
}
variants.sort();
if variants.len() != 2 {
let guar = tcx
.dcx()
.err(format!("the only or-pattern types allowed are two range patterns that are directly connected at their overflow site"));
return Err(error(cx, LayoutError::ReferencesError(guar)));
}
let mut first = variants[0];
let mut second = variants[1];
if second.0
== layout.size.truncate(layout.size.signed_int_min() as u128)
{
(second, first) = (first, second);
}
if layout.size.sign_extend(first.1) >= layout.size.sign_extend(second.0)
{
let guar = tcx.dcx().err(format!(
"only non-overlapping pattern type ranges are allowed at present"
));
return Err(error(cx, LayoutError::ReferencesError(guar)));
}
if layout.size.signed_int_max() as u128 != second.1 {
let guar = tcx.dcx().err(format!(
"one pattern needs to end at `{ty}::MAX`, but was {} instead",
second.1
));
return Err(error(cx, LayoutError::ReferencesError(guar)));
}
scalar.valid_range_mut().start = second.0;
scalar.valid_range_mut().end = first.1;
let niche = Niche {
offset: Size::ZERO,
value: scalar.primitive(),
valid_range: scalar.valid_range(cx),
};
layout.largest_niche = Some(niche);
} else {
bug!(
"pattern type with range but not scalar layout: {ty:?}, {layout:?}"
)
}
}
ty::PatternKind::NotNull => bug!("or patterns can't contain `!null` patterns"),
ty::PatternKind::Or(..) => bug!("patterns cannot have nested or patterns"),
},
}
layout.fields = FieldsShape::Arbitrary {
offsets: [Size::ZERO].into_iter().collect(),
in_memory_order: [FieldIdx::new(0)].into_iter().collect(),
};
tcx.mk_layout(layout)
}
ty::Bool => tcx.mk_layout(LayoutData::scalar(
cx,
Scalar::Initialized {
value: Int(I8, false),
valid_range: WrappingRange { start: 0, end: 1 },
},
)),
ty::Char => tcx.mk_layout(LayoutData::scalar(
cx,
Scalar::Initialized {
value: Int(I32, false),
valid_range: WrappingRange { start: 0, end: 0x10FFFF },
},
)),
ty::Int(ity) => scalar(Int(abi::Integer::from_int_ty(dl, ity), true)),
ty::Uint(ity) => scalar(Int(abi::Integer::from_uint_ty(dl, ity), false)),
ty::Float(fty) => scalar(Float(abi::Float::from_float_ty(fty))),
ty::FnPtr(..) => {
let mut ptr = scalar_unit(Pointer(dl.instruction_address_space));
ptr.valid_range_mut().start = 1;
tcx.mk_layout(LayoutData::scalar(cx, ptr))
}
ty::Never => tcx.mk_layout(LayoutData::never_type(cx)),
ty::Ref(_, pointee, _) | ty::RawPtr(pointee, _) => {
let mut data_ptr = scalar_unit(Pointer(AddressSpace::ZERO));
if !ty.is_raw_ptr() {
data_ptr.valid_range_mut().start = 1;
}
if pointee.is_sized(tcx, cx.typing_env) {
return Ok(tcx.mk_layout(LayoutData::scalar(cx, data_ptr)));
}
let metadata = if let Some(metadata_def_id) = tcx.lang_items().metadata_type() {
let pointee_metadata =
Ty::new_projection(tcx, ty::IsRigid::No, metadata_def_id, [pointee]);
let metadata_ty = match tcx.try_normalize_erasing_regions(
cx.typing_env,
Unnormalized::new_wip(pointee_metadata),
) {
Ok(metadata_ty) => metadata_ty,
Err(mut err) => {
match tcx.try_normalize_erasing_regions(
cx.typing_env,
Unnormalized::new_wip(tcx.struct_tail_raw(
pointee,
&ObligationCause::dummy(),
|ty| ty.skip_norm_wip(),
|| {},
)),
) {
Ok(_) => {}
Err(better_err) => {
err = better_err;
}
}
return Err(error(cx, LayoutError::NormalizationFailure(pointee, err)));
}
};
let metadata_layout = cx.layout_of(metadata_ty)?;
if metadata_layout.is_1zst() {
return Ok(tcx.mk_layout(LayoutData::scalar(cx, data_ptr)));
}
let BackendRepr::Scalar(metadata) = metadata_layout.backend_repr else {
return Err(error(cx, LayoutError::Unknown(pointee)));
};
metadata
} else {
let unsized_part = tcx.struct_tail_for_codegen(pointee, cx.typing_env);
match unsized_part.kind() {
ty::Foreign(..) => {
return Ok(tcx.mk_layout(LayoutData::scalar(cx, data_ptr)));
}
ty::Slice(_) | ty::Str => scalar_unit(Int(dl.ptr_sized_integer(), false)),
ty::Dynamic(..) => {
let mut vtable = scalar_unit(Pointer(AddressSpace::ZERO));
vtable.valid_range_mut().start = 1;
vtable
}
_ => {
return Err(error(cx, LayoutError::Unknown(pointee)));
}
}
};
tcx.mk_layout(LayoutData::scalar_pair(cx, data_ptr, metadata))
}
ty::Array(element, count) => {
let count = extract_const_value(cx, ty, count)?
.try_to_target_usize(tcx)
.ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?;
let element = cx.layout_of(element)?;
map_layout(cx.calc.array_like(&element, Some(count)))?
}
ty::Slice(element) => {
let element = cx.layout_of(element)?;
map_layout(cx.calc.array_like(&element, None).map(|mut layout| {
layout.randomization_seed = Hash64::new(0x2dcba99c39784102);
layout
}))?
}
ty::Str => {
let element = scalar(Int(I8, false));
map_layout(cx.calc.array_like(&element, None).map(|mut layout| {
layout.randomization_seed = Hash64::new(0xc1325f37d127be22);
layout
}))?
}
ty::FnDef(..) | ty::Dynamic(_, _) | ty::Foreign(..) => {
let sized = matches!(ty.kind(), ty::FnDef(..));
tcx.mk_layout(LayoutData::unit(cx, sized))
}
ty::Coroutine(def_id, args) => {
match cx.typing_env.typing_mode() {
ty::TypingMode::Codegen => {}
ty::TypingMode::Coherence
| ty::TypingMode::Typeck { .. }
| ty::TypingMode::PostTypeckUntilBorrowck { .. }
| ty::TypingMode::PostBorrowck { .. }
| ty::TypingMode::Reflection
| ty::TypingMode::ErasedNotCoherence(_)
| ty::TypingMode::PostAnalysis => {
return Err(error(cx, LayoutError::TooGeneric(ty)));
}
}
use crate::rustc_middle::ty::layout::PrimitiveExt as _;
let info = tcx.coroutine_layout(def_id, args)?;
let local_layouts = info
.field_tys
.iter()
.map(|local| {
let field_ty = EarlyBinder::bind(tcx, local.ty);
let uninit_ty =
Ty::new_maybe_uninit(tcx, field_ty.instantiate(tcx, args).skip_norm_wip());
cx.spanned_layout_of(uninit_ty, local.source_info.span)
})
.collect::<Result<IndexVec<_, _>, _>>()?;
let prefix_layouts = args
.as_coroutine()
.upvar_tys()
.iter()
.map(|ty| cx.layout_of(ty))
.collect::<Result<IndexVec<_, _>, _>>()?;
let layout = cx
.calc
.coroutine(
&local_layouts,
prefix_layouts,
&info.variant_fields,
&info.storage_conflicts,
|tag| TyAndLayout {
ty: tag.primitive().to_ty(tcx),
layout: tcx.mk_layout(LayoutData::scalar(cx, tag)),
},
)
.map(|mut layout| {
layout.randomization_seed = tcx.def_path_hash(def_id).0.to_smaller_hash();
debug!("coroutine layout ({:?}): {:#?}", ty, layout);
layout
});
map_layout(layout)?
}
ty::Closure(_, args) => univariant(args.as_closure().upvar_tys(), StructKind::AlwaysSized)?,
ty::CoroutineClosure(_, args) => {
univariant(args.as_coroutine_closure().upvar_tys(), StructKind::AlwaysSized)?
}
ty::Tuple(tys) => {
let kind =
if tys.len() == 0 { StructKind::AlwaysSized } else { StructKind::MaybeUnsized };
univariant(tys, kind)?
}
ty::Adt(def, _args) if def.repr().scalable() => {
let Some((element_count, element_ty, number_of_vectors)) =
ty.scalable_vector_parts(tcx)
else {
let guar = tcx
.dcx()
.delayed_bug("`#[rustc_scalable_vector]` was applied to an invalid type");
return Err(error(cx, LayoutError::ReferencesError(guar)));
};
let element_layout = cx.layout_of(element_ty)?;
map_layout(cx.calc.scalable_vector_type(
element_layout,
element_count as u64,
number_of_vectors,
))?
}
ty::Adt(def, args) if def.repr().simd() => {
let Some(ty::Array(e_ty, e_len)) = def
.is_struct()
.then(|| &def.variant(FIRST_VARIANT).fields)
.filter(|fields| fields.len() == 1)
.map(|fields| *fields[FieldIdx::ZERO].ty(tcx, args).skip_norm_wip().kind())
else {
let guar = tcx.dcx().delayed_bug("#[repr(simd)] was applied to an invalid ADT");
return Err(error(cx, LayoutError::ReferencesError(guar)));
};
let e_len = extract_const_value(cx, ty, e_len)?
.try_to_target_usize(tcx)
.ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?;
let e_ly = cx.layout_of(e_ty)?;
if let Some(limit) = find_attr!(
tcx, def.did(),
RustcSimdMonomorphizeLaneLimit(limit) => limit
) {
if !limit.value_within_limit(e_len as usize) {
return Err(map_error(
&cx,
ty,
crate::rustc_abi::LayoutCalculatorError::OversizedSimdType { max_lanes: limit.0 },
));
}
}
map_layout(cx.calc.simd_type(e_ly, e_len, def.repr().packed()))?
}
ty::Adt(def, args) => {
let variants = def
.variants()
.iter()
.map(|v| {
v.fields
.iter()
.map(|field| cx.layout_of(field.ty(tcx, args).skip_norm_wip()))
.collect::<Result<IndexVec<_, _>, _>>()
})
.collect::<Result<IndexVec<VariantIdx, _>, _>>()?;
if def.is_union() {
if def.repr().pack.is_some() && def.repr().align.is_some() {
let guar = tcx.dcx().span_delayed_bug(
tcx.def_span(def.did()),
"union cannot be packed and aligned",
);
return Err(error(cx, LayoutError::ReferencesError(guar)));
}
return map_layout(cx.calc.layout_of_union(&def.repr(), &variants));
}
let is_special_no_niche = def.is_unsafe_cell() || def.is_unsafe_pinned();
let discr_range_of_repr = |min: RangeFrom<i128>, max: RangeToInclusive<u128>| {
abi::Integer::discr_range_of_repr(tcx, ty, &def.repr(), min.start, max.last)
};
let discriminants_iter = || {
def.is_enum()
.then(|| def.discriminants(tcx).map(|(v, d)| (v, d.val)))
.into_iter()
.flatten()
};
let maybe_unsized = def.is_struct()
&& def.non_enum_variant().tail_opt().is_some_and(|last_field| {
let typing_env = ty::TypingEnv::new(
tcx.param_env_normalized_for_post_analysis(def.did()),
cx.typing_env.typing_mode(),
);
!tcx.type_of(last_field.did)
.instantiate_identity()
.skip_norm_wip()
.is_sized(tcx, typing_env)
});
let layout = cx
.calc
.layout_of_struct_or_enum(
&def.repr(),
&variants,
def.is_enum(),
is_special_no_niche,
discr_range_of_repr,
discriminants_iter(),
!maybe_unsized,
)
.map_err(|err| map_error(cx, ty, err))?;
if !maybe_unsized && layout.is_unsized() {
bug!("got unsized layout for type that cannot be unsized {ty:?}: {layout:#?}");
}
if cfg!(debug_assertions)
&& maybe_unsized
&& def
.non_enum_variant()
.tail()
.ty(tcx, args)
.skip_norm_wip()
.is_sized(tcx, cx.typing_env)
{
let mut variants = variants;
let tail_replacement = cx.layout_of(Ty::new_slice(tcx, tcx.types.u8)).unwrap();
*variants[FIRST_VARIANT].raw.last_mut().unwrap() = tail_replacement;
let Ok(unsized_layout) = cx.calc.layout_of_struct_or_enum(
&def.repr(),
&variants,
def.is_enum(),
is_special_no_niche,
discr_range_of_repr,
discriminants_iter(),
!maybe_unsized,
) else {
bug!("failed to compute unsized layout of {ty:?}");
};
let FieldsShape::Arbitrary { offsets: sized_offsets, .. } = &layout.fields else {
bug!("unexpected FieldsShape for sized layout of {ty:?}: {:?}", layout.fields);
};
let FieldsShape::Arbitrary { offsets: unsized_offsets, .. } =
&unsized_layout.fields
else {
bug!(
"unexpected FieldsShape for unsized layout of {ty:?}: {:?}",
unsized_layout.fields
);
};
let (sized_tail, sized_fields) = sized_offsets.raw.split_last().unwrap();
let (unsized_tail, unsized_fields) = unsized_offsets.raw.split_last().unwrap();
if sized_fields != unsized_fields {
bug!("unsizing {ty:?} changed field order!\n{layout:?}\n{unsized_layout:?}");
}
if sized_tail < unsized_tail {
bug!("unsizing {ty:?} moved tail backwards!\n{layout:?}\n{unsized_layout:?}");
}
}
tcx.mk_layout(layout)
}
ty::UnsafeBinder(bound_ty) => {
let ty = tcx.instantiate_bound_regions_with_erased(bound_ty.into());
cx.layout_of(ty)?.layout
}
ty::Param(_) | ty::Placeholder(..) => {
return Err(error(cx, LayoutError::TooGeneric(ty)));
}
ty::Alias(..) => {
let err = if ty.has_param() || !cx.typing_env.param_env.is_empty() {
LayoutError::TooGeneric(ty)
} else {
LayoutError::ReferencesError(cx.tcx().dcx().delayed_bug(format!(
"unexpected rigid alias in layout_of after normalization: {ty:?}"
)))
};
return Err(error(cx, err));
}
ty::Bound(..) | ty::CoroutineWitness(..) | ty::Infer(_) | ty::Error(_) => {
bug!("layout_of: unexpected type `{ty}`")
}
})
}