internal: Move layout logic from hir-def to hir-ty
This commit is contained in:
parent
b218009f46
commit
0bb9a17312
@ -13,7 +13,7 @@
|
||||
};
|
||||
use intern::Interned;
|
||||
use la_arena::{Arena, ArenaMap};
|
||||
use rustc_abi::{Integer, IntegerType};
|
||||
use rustc_abi::{Align, Integer, IntegerType, ReprFlags, ReprOptions};
|
||||
use syntax::ast::{self, HasName, HasVisibility};
|
||||
|
||||
use crate::{
|
||||
@ -22,7 +22,6 @@
|
||||
db::DefDatabase,
|
||||
item_tree::{AttrOwner, Field, FieldAstId, Fields, ItemTree, ModItem, RawVisibilityId},
|
||||
lang_item::LangItem,
|
||||
layout::{Align, ReprFlags, ReprOptions},
|
||||
nameres::diagnostics::DefDiagnostic,
|
||||
src::HasChildSource,
|
||||
src::HasSource,
|
||||
|
@ -1,98 +0,0 @@
|
||||
//! Definitions needed for computing data layout of types.
|
||||
|
||||
use std::cmp;
|
||||
|
||||
use la_arena::{Idx, RawIdx};
|
||||
pub use rustc_abi::{
|
||||
Abi, AbiAndPrefAlign, AddressSpace, Align, Endian, FieldsShape, Integer, IntegerType,
|
||||
LayoutCalculator, Niche, Primitive, ReprFlags, ReprOptions, Scalar, Size, StructKind,
|
||||
TargetDataLayout, TargetDataLayoutErrors, WrappingRange,
|
||||
};
|
||||
|
||||
use crate::LocalEnumVariantId;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct RustcEnumVariantIdx(pub LocalEnumVariantId);
|
||||
|
||||
impl rustc_index::vec::Idx for RustcEnumVariantIdx {
|
||||
fn new(idx: usize) -> Self {
|
||||
RustcEnumVariantIdx(Idx::from_raw(RawIdx::from(idx as u32)))
|
||||
}
|
||||
|
||||
fn index(self) -> usize {
|
||||
u32::from(self.0.into_raw()) as usize
|
||||
}
|
||||
}
|
||||
|
||||
pub type Layout = rustc_abi::LayoutS<RustcEnumVariantIdx>;
|
||||
pub type TagEncoding = rustc_abi::TagEncoding<RustcEnumVariantIdx>;
|
||||
pub type Variants = rustc_abi::Variants<RustcEnumVariantIdx>;
|
||||
|
||||
pub trait IntegerExt {
|
||||
fn repr_discr(
|
||||
dl: &TargetDataLayout,
|
||||
repr: &ReprOptions,
|
||||
min: i128,
|
||||
max: i128,
|
||||
) -> Result<(Integer, bool), LayoutError>;
|
||||
}
|
||||
|
||||
impl IntegerExt for Integer {
|
||||
/// Finds the appropriate Integer type and signedness for the given
|
||||
/// signed discriminant range and `#[repr]` attribute.
|
||||
/// N.B.: `u128` values above `i128::MAX` will be treated as signed, but
|
||||
/// that shouldn't affect anything, other than maybe debuginfo.
|
||||
fn repr_discr(
|
||||
dl: &TargetDataLayout,
|
||||
repr: &ReprOptions,
|
||||
min: i128,
|
||||
max: i128,
|
||||
) -> Result<(Integer, bool), LayoutError> {
|
||||
// Theoretically, negative values could be larger in unsigned representation
|
||||
// than the unsigned representation of the signed minimum. However, if there
|
||||
// are any negative values, the only valid unsigned representation is u128
|
||||
// which can fit all i128 values, so the result remains unaffected.
|
||||
let unsigned_fit = Integer::fit_unsigned(cmp::max(min as u128, max as u128));
|
||||
let signed_fit = cmp::max(Integer::fit_signed(min), Integer::fit_signed(max));
|
||||
|
||||
if let Some(ity) = repr.int {
|
||||
let discr = Integer::from_attr(dl, ity);
|
||||
let fit = if ity.is_signed() { signed_fit } else { unsigned_fit };
|
||||
if discr < fit {
|
||||
return Err(LayoutError::UserError(
|
||||
"Integer::repr_discr: `#[repr]` hint too small for \
|
||||
discriminant range of enum "
|
||||
.to_string(),
|
||||
));
|
||||
}
|
||||
return Ok((discr, ity.is_signed()));
|
||||
}
|
||||
|
||||
let at_least = if repr.c() {
|
||||
// This is usually I32, however it can be different on some platforms,
|
||||
// notably hexagon and arm-none/thumb-none
|
||||
dl.c_enum_min_size
|
||||
} else {
|
||||
// repr(Rust) enums try to be as small as possible
|
||||
Integer::I8
|
||||
};
|
||||
|
||||
// If there are no negative values, we can use the unsigned fit.
|
||||
Ok(if min >= 0 {
|
||||
(cmp::max(unsigned_fit, at_least), false)
|
||||
} else {
|
||||
(cmp::max(signed_fit, at_least), true)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||
pub enum LayoutError {
|
||||
UserError(String),
|
||||
SizeOverflow,
|
||||
TargetLayoutNotAvailable,
|
||||
HasPlaceholder,
|
||||
HasErrorType,
|
||||
NotImplemented,
|
||||
Unknown,
|
||||
}
|
@ -29,7 +29,6 @@ macro_rules! eprintln {
|
||||
pub mod data;
|
||||
pub mod generics;
|
||||
pub mod lang_item;
|
||||
pub mod layout;
|
||||
|
||||
pub mod hir;
|
||||
pub use self::hir::type_ref;
|
||||
@ -46,6 +45,8 @@ macro_rules! eprintln {
|
||||
pub mod find_path;
|
||||
pub mod import_map;
|
||||
|
||||
pub use rustc_abi as layout;
|
||||
|
||||
#[cfg(test)]
|
||||
mod test_db;
|
||||
#[cfg(test)]
|
||||
|
@ -9,14 +9,12 @@
|
||||
use crate::{
|
||||
body::LowerCtx,
|
||||
lang_item::LangItemTarget,
|
||||
type_ref::{ConstRefOrPath, LifetimeRef},
|
||||
type_ref::{ConstRefOrPath, LifetimeRef, TypeBound, TypeRef},
|
||||
};
|
||||
use hir_expand::name::Name;
|
||||
use intern::Interned;
|
||||
use syntax::ast;
|
||||
|
||||
use crate::type_ref::{TypeBound, TypeRef};
|
||||
|
||||
pub use hir_expand::mod_path::{path, ModPath, PathKind};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
|
@ -5,11 +5,9 @@
|
||||
|
||||
use base_db::{impl_intern_key, salsa, CrateId, Upcast};
|
||||
use hir_def::{
|
||||
db::DefDatabase,
|
||||
hir::ExprId,
|
||||
layout::{Layout, LayoutError, TargetDataLayout},
|
||||
AdtId, BlockId, ConstId, ConstParamId, DefWithBodyId, EnumVariantId, FunctionId, GenericDefId,
|
||||
ImplId, LifetimeParamId, LocalFieldId, TypeOrConstParamId, VariantId,
|
||||
db::DefDatabase, hir::ExprId, layout::TargetDataLayout, AdtId, BlockId, ConstId, ConstParamId,
|
||||
DefWithBodyId, EnumVariantId, FunctionId, GenericDefId, ImplId, LifetimeParamId, LocalFieldId,
|
||||
TypeOrConstParamId, VariantId,
|
||||
};
|
||||
use la_arena::ArenaMap;
|
||||
use smallvec::SmallVec;
|
||||
@ -17,6 +15,7 @@
|
||||
use crate::{
|
||||
chalk_db,
|
||||
consteval::ConstEvalError,
|
||||
layout::{Layout, LayoutError},
|
||||
method_resolution::{InherentImpls, TraitImpls, TyFingerprint},
|
||||
mir::{BorrowckResult, MirBody, MirLowerError},
|
||||
Binders, CallableDefId, ClosureId, Const, FnDefId, GenericArg, ImplTraitId, InferenceResult,
|
||||
|
@ -18,11 +18,11 @@
|
||||
|
||||
use chalk_ir::{cast::Cast, DebruijnIndex, Mutability, Safety, Scalar, TypeFlags};
|
||||
use either::Either;
|
||||
use hir_def::hir::LabelId;
|
||||
use hir_def::{
|
||||
body::Body,
|
||||
builtin_type::{BuiltinInt, BuiltinType, BuiltinUint},
|
||||
data::{ConstData, StaticData},
|
||||
hir::LabelId,
|
||||
hir::{BindingAnnotation, BindingId, ExprId, ExprOrPatId, PatId},
|
||||
lang_item::{LangItem, LangItemTarget},
|
||||
layout::Integer,
|
||||
|
@ -4,16 +4,19 @@
|
||||
use chalk_ir::{AdtId, TyKind};
|
||||
use hir_def::{
|
||||
layout::{
|
||||
Abi, FieldsShape, Integer, Layout, LayoutCalculator, LayoutError, Primitive, ReprOptions,
|
||||
RustcEnumVariantIdx, Scalar, Size, StructKind, TargetDataLayout, Variants, WrappingRange,
|
||||
Abi, FieldsShape, Integer, LayoutCalculator, LayoutS, Primitive, ReprOptions, Scalar, Size,
|
||||
StructKind, TargetDataLayout, WrappingRange,
|
||||
},
|
||||
LocalFieldId,
|
||||
LocalEnumVariantId, LocalFieldId,
|
||||
};
|
||||
use la_arena::{Idx, RawIdx};
|
||||
use stdx::never;
|
||||
|
||||
use crate::{consteval::try_const_usize, db::HirDatabase, Interner, Substitution, Ty};
|
||||
use crate::{
|
||||
consteval::try_const_usize, db::HirDatabase, layout::adt::struct_variant_idx, Interner,
|
||||
Substitution, Ty,
|
||||
};
|
||||
|
||||
use self::adt::struct_variant_idx;
|
||||
pub use self::{
|
||||
adt::{layout_of_adt_query, layout_of_adt_recover},
|
||||
target::target_data_layout_query,
|
||||
@ -28,6 +31,34 @@ macro_rules! user_error {
|
||||
mod adt;
|
||||
mod target;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct RustcEnumVariantIdx(pub LocalEnumVariantId);
|
||||
|
||||
impl rustc_index::vec::Idx for RustcEnumVariantIdx {
|
||||
fn new(idx: usize) -> Self {
|
||||
RustcEnumVariantIdx(Idx::from_raw(RawIdx::from(idx as u32)))
|
||||
}
|
||||
|
||||
fn index(self) -> usize {
|
||||
u32::from(self.0.into_raw()) as usize
|
||||
}
|
||||
}
|
||||
|
||||
pub type Layout = LayoutS<RustcEnumVariantIdx>;
|
||||
pub type TagEncoding = hir_def::layout::TagEncoding<RustcEnumVariantIdx>;
|
||||
pub type Variants = hir_def::layout::Variants<RustcEnumVariantIdx>;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||
pub enum LayoutError {
|
||||
UserError(String),
|
||||
SizeOverflow,
|
||||
TargetLayoutNotAvailable,
|
||||
HasPlaceholder,
|
||||
HasErrorType,
|
||||
NotImplemented,
|
||||
Unknown,
|
||||
}
|
||||
|
||||
struct LayoutCx<'a> {
|
||||
krate: CrateId,
|
||||
target: &'a TargetDataLayout,
|
||||
@ -45,14 +76,6 @@ fn current_data_layout(&self) -> &'a TargetDataLayout {
|
||||
}
|
||||
}
|
||||
|
||||
fn scalar_unit(dl: &TargetDataLayout, value: Primitive) -> Scalar {
|
||||
Scalar::Initialized { value, valid_range: WrappingRange::full(value.size(dl)) }
|
||||
}
|
||||
|
||||
fn scalar(dl: &TargetDataLayout, value: Primitive) -> Layout {
|
||||
Layout::scalar(dl, scalar_unit(dl, value))
|
||||
}
|
||||
|
||||
pub fn layout_of_ty(db: &dyn HirDatabase, ty: &Ty, krate: CrateId) -> Result<Layout, LayoutError> {
|
||||
let Some(target) = db.target_data_layout(krate) else { return Err(LayoutError::TargetLayoutNotAvailable) };
|
||||
let cx = LayoutCx { krate, target: &target };
|
||||
@ -287,5 +310,13 @@ fn field_ty(
|
||||
db.field_types(def)[fd].clone().substitute(Interner, subst)
|
||||
}
|
||||
|
||||
fn scalar_unit(dl: &TargetDataLayout, value: Primitive) -> Scalar {
|
||||
Scalar::Initialized { value, valid_range: WrappingRange::full(value.size(dl)) }
|
||||
}
|
||||
|
||||
fn scalar(dl: &TargetDataLayout, value: Primitive) -> Layout {
|
||||
Layout::scalar(dl, scalar_unit(dl, value))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
@ -1,16 +1,21 @@
|
||||
//! Compute the binary representation of structs, unions and enums
|
||||
|
||||
use std::ops::Bound;
|
||||
use std::{cmp, ops::Bound};
|
||||
|
||||
use hir_def::{
|
||||
data::adt::VariantData,
|
||||
layout::{Integer, IntegerExt, Layout, LayoutCalculator, LayoutError, RustcEnumVariantIdx},
|
||||
layout::{Integer, LayoutCalculator, ReprOptions, TargetDataLayout},
|
||||
AdtId, EnumVariantId, HasModule, LocalEnumVariantId, VariantId,
|
||||
};
|
||||
use la_arena::RawIdx;
|
||||
use smallvec::SmallVec;
|
||||
|
||||
use crate::{db::HirDatabase, lang_items::is_unsafe_cell, layout::field_ty, Substitution};
|
||||
use crate::{
|
||||
db::HirDatabase,
|
||||
lang_items::is_unsafe_cell,
|
||||
layout::{field_ty, Layout, LayoutError, RustcEnumVariantIdx},
|
||||
Substitution,
|
||||
};
|
||||
|
||||
use super::{layout_of_ty, LayoutCx};
|
||||
|
||||
@ -73,7 +78,7 @@ pub fn layout_of_adt_query(
|
||||
is_enum,
|
||||
is_unsafe_cell(db, def),
|
||||
layout_scalar_valid_range(db, def),
|
||||
|min, max| Integer::repr_discr(&dl, &repr, min, max).unwrap_or((Integer::I8, false)),
|
||||
|min, max| repr_discr(&dl, &repr, min, max).unwrap_or((Integer::I8, false)),
|
||||
variants.iter_enumerated().filter_map(|(id, _)| {
|
||||
let AdtId::EnumId(e) = def else { return None };
|
||||
let d =
|
||||
@ -125,3 +130,50 @@ pub fn layout_of_adt_recover(
|
||||
) -> Result<Layout, LayoutError> {
|
||||
user_error!("infinite sized recursive type");
|
||||
}
|
||||
|
||||
/// Finds the appropriate Integer type and signedness for the given
|
||||
/// signed discriminant range and `#[repr]` attribute.
|
||||
/// N.B.: `u128` values above `i128::MAX` will be treated as signed, but
|
||||
/// that shouldn't affect anything, other than maybe debuginfo.
|
||||
fn repr_discr(
|
||||
dl: &TargetDataLayout,
|
||||
repr: &ReprOptions,
|
||||
min: i128,
|
||||
max: i128,
|
||||
) -> Result<(Integer, bool), LayoutError> {
|
||||
// Theoretically, negative values could be larger in unsigned representation
|
||||
// than the unsigned representation of the signed minimum. However, if there
|
||||
// are any negative values, the only valid unsigned representation is u128
|
||||
// which can fit all i128 values, so the result remains unaffected.
|
||||
let unsigned_fit = Integer::fit_unsigned(cmp::max(min as u128, max as u128));
|
||||
let signed_fit = cmp::max(Integer::fit_signed(min), Integer::fit_signed(max));
|
||||
|
||||
if let Some(ity) = repr.int {
|
||||
let discr = Integer::from_attr(dl, ity);
|
||||
let fit = if ity.is_signed() { signed_fit } else { unsigned_fit };
|
||||
if discr < fit {
|
||||
return Err(LayoutError::UserError(
|
||||
"Integer::repr_discr: `#[repr]` hint too small for \
|
||||
discriminant range of enum "
|
||||
.to_string(),
|
||||
));
|
||||
}
|
||||
return Ok((discr, ity.is_signed()));
|
||||
}
|
||||
|
||||
let at_least = if repr.c() {
|
||||
// This is usually I32, however it can be different on some platforms,
|
||||
// notably hexagon and arm-none/thumb-none
|
||||
dl.c_enum_min_size
|
||||
} else {
|
||||
// repr(Rust) enums try to be as small as possible
|
||||
Integer::I8
|
||||
};
|
||||
|
||||
// If there are no negative values, we can use the unsigned fit.
|
||||
Ok(if min >= 0 {
|
||||
(cmp::max(unsigned_fit, at_least), false)
|
||||
} else {
|
||||
(cmp::max(signed_fit, at_least), true)
|
||||
})
|
||||
}
|
||||
|
@ -2,12 +2,14 @@
|
||||
|
||||
use base_db::fixture::WithFixture;
|
||||
use chalk_ir::{AdtId, TyKind};
|
||||
use hir_def::{
|
||||
db::DefDatabase,
|
||||
layout::{Layout, LayoutError},
|
||||
};
|
||||
use hir_def::db::DefDatabase;
|
||||
|
||||
use crate::{db::HirDatabase, test_db::TestDB, Interner, Substitution};
|
||||
use crate::{
|
||||
db::HirDatabase,
|
||||
layout::{Layout, LayoutError},
|
||||
test_db::TestDB,
|
||||
Interner, Substitution,
|
||||
};
|
||||
|
||||
use super::layout_of_ty;
|
||||
|
||||
|
@ -10,7 +10,7 @@
|
||||
use hir_def::{
|
||||
builtin_type::BuiltinType,
|
||||
lang_item::{lang_attr, LangItem},
|
||||
layout::{Layout, LayoutError, RustcEnumVariantIdx, TagEncoding, Variants},
|
||||
layout::{TagEncoding, Variants},
|
||||
AdtId, DefWithBodyId, EnumVariantId, FunctionId, HasModule, ItemContainerId, Lookup, VariantId,
|
||||
};
|
||||
use intern::Interned;
|
||||
@ -21,7 +21,7 @@
|
||||
db::HirDatabase,
|
||||
from_placeholder_idx,
|
||||
infer::{normalize, PointerCast},
|
||||
layout::layout_of_ty,
|
||||
layout::{layout_of_ty, Layout, LayoutError, RustcEnumVariantIdx},
|
||||
mapping::from_chalk,
|
||||
method_resolution::{is_dyn_method, lookup_impl_method},
|
||||
traits::FnTrait,
|
||||
|
@ -11,7 +11,6 @@
|
||||
RecordFieldPat, RecordLitField,
|
||||
},
|
||||
lang_item::{LangItem, LangItemTarget},
|
||||
layout::LayoutError,
|
||||
path::Path,
|
||||
resolver::{resolver_for_expr, ResolveValueResult, ValueNs},
|
||||
AdtId, DefWithBodyId, EnumVariantId, HasModule, ItemContainerId, LocalFieldId, TraitId,
|
||||
@ -26,7 +25,7 @@
|
||||
display::HirDisplay,
|
||||
infer::{CaptureKind, CapturedItem, TypeMismatch},
|
||||
inhabitedness::is_ty_uninhabited_from,
|
||||
layout::layout_of_ty,
|
||||
layout::{layout_of_ty, LayoutError},
|
||||
mapping::ToChalk,
|
||||
static_lifetime,
|
||||
utils::generics,
|
||||
|
@ -45,7 +45,7 @@
|
||||
hir::{BindingAnnotation, BindingId, ExprOrPatId, LabelId, Pat},
|
||||
item_tree::ItemTreeNode,
|
||||
lang_item::{LangItem, LangItemTarget},
|
||||
layout::{Layout, LayoutError, ReprOptions},
|
||||
layout::ReprOptions,
|
||||
nameres::{self, diagnostics::DefDiagnostic, ModuleOrigin},
|
||||
per_ns::PerNs,
|
||||
resolver::{HasResolver, Resolver},
|
||||
@ -61,7 +61,7 @@
|
||||
consteval::{try_const_usize, unknown_const_as_generic, ConstEvalError, ConstExt},
|
||||
diagnostics::BodyValidationDiagnostic,
|
||||
display::HexifiedConst,
|
||||
layout::layout_of_ty,
|
||||
layout::{layout_of_ty, Layout, LayoutError},
|
||||
method_resolution::{self, TyFingerprint},
|
||||
mir::{self, interpret_mir},
|
||||
primitive::UintTy,
|
||||
|
Loading…
Reference in New Issue
Block a user