internal: Move layout logic from hir-def to hir-ty

This commit is contained in:
Lukas Wirth 2023-04-16 12:21:12 +02:00
parent b218009f46
commit 0bb9a17312
12 changed files with 121 additions and 138 deletions

View File

@ -13,7 +13,7 @@
}; };
use intern::Interned; use intern::Interned;
use la_arena::{Arena, ArenaMap}; 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 syntax::ast::{self, HasName, HasVisibility};
use crate::{ use crate::{
@ -22,7 +22,6 @@
db::DefDatabase, db::DefDatabase,
item_tree::{AttrOwner, Field, FieldAstId, Fields, ItemTree, ModItem, RawVisibilityId}, item_tree::{AttrOwner, Field, FieldAstId, Fields, ItemTree, ModItem, RawVisibilityId},
lang_item::LangItem, lang_item::LangItem,
layout::{Align, ReprFlags, ReprOptions},
nameres::diagnostics::DefDiagnostic, nameres::diagnostics::DefDiagnostic,
src::HasChildSource, src::HasChildSource,
src::HasSource, src::HasSource,

View File

@ -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,
}

View File

@ -29,7 +29,6 @@ macro_rules! eprintln {
pub mod data; pub mod data;
pub mod generics; pub mod generics;
pub mod lang_item; pub mod lang_item;
pub mod layout;
pub mod hir; pub mod hir;
pub use self::hir::type_ref; pub use self::hir::type_ref;
@ -46,6 +45,8 @@ macro_rules! eprintln {
pub mod find_path; pub mod find_path;
pub mod import_map; pub mod import_map;
pub use rustc_abi as layout;
#[cfg(test)] #[cfg(test)]
mod test_db; mod test_db;
#[cfg(test)] #[cfg(test)]

View File

@ -9,14 +9,12 @@
use crate::{ use crate::{
body::LowerCtx, body::LowerCtx,
lang_item::LangItemTarget, lang_item::LangItemTarget,
type_ref::{ConstRefOrPath, LifetimeRef}, type_ref::{ConstRefOrPath, LifetimeRef, TypeBound, TypeRef},
}; };
use hir_expand::name::Name; use hir_expand::name::Name;
use intern::Interned; use intern::Interned;
use syntax::ast; use syntax::ast;
use crate::type_ref::{TypeBound, TypeRef};
pub use hir_expand::mod_path::{path, ModPath, PathKind}; pub use hir_expand::mod_path::{path, ModPath, PathKind};
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]

View File

@ -5,11 +5,9 @@
use base_db::{impl_intern_key, salsa, CrateId, Upcast}; use base_db::{impl_intern_key, salsa, CrateId, Upcast};
use hir_def::{ use hir_def::{
db::DefDatabase, db::DefDatabase, hir::ExprId, layout::TargetDataLayout, AdtId, BlockId, ConstId, ConstParamId,
hir::ExprId, DefWithBodyId, EnumVariantId, FunctionId, GenericDefId, ImplId, LifetimeParamId, LocalFieldId,
layout::{Layout, LayoutError, TargetDataLayout}, TypeOrConstParamId, VariantId,
AdtId, BlockId, ConstId, ConstParamId, DefWithBodyId, EnumVariantId, FunctionId, GenericDefId,
ImplId, LifetimeParamId, LocalFieldId, TypeOrConstParamId, VariantId,
}; };
use la_arena::ArenaMap; use la_arena::ArenaMap;
use smallvec::SmallVec; use smallvec::SmallVec;
@ -17,6 +15,7 @@
use crate::{ use crate::{
chalk_db, chalk_db,
consteval::ConstEvalError, consteval::ConstEvalError,
layout::{Layout, LayoutError},
method_resolution::{InherentImpls, TraitImpls, TyFingerprint}, method_resolution::{InherentImpls, TraitImpls, TyFingerprint},
mir::{BorrowckResult, MirBody, MirLowerError}, mir::{BorrowckResult, MirBody, MirLowerError},
Binders, CallableDefId, ClosureId, Const, FnDefId, GenericArg, ImplTraitId, InferenceResult, Binders, CallableDefId, ClosureId, Const, FnDefId, GenericArg, ImplTraitId, InferenceResult,

View File

@ -18,11 +18,11 @@
use chalk_ir::{cast::Cast, DebruijnIndex, Mutability, Safety, Scalar, TypeFlags}; use chalk_ir::{cast::Cast, DebruijnIndex, Mutability, Safety, Scalar, TypeFlags};
use either::Either; use either::Either;
use hir_def::hir::LabelId;
use hir_def::{ use hir_def::{
body::Body, body::Body,
builtin_type::{BuiltinInt, BuiltinType, BuiltinUint}, builtin_type::{BuiltinInt, BuiltinType, BuiltinUint},
data::{ConstData, StaticData}, data::{ConstData, StaticData},
hir::LabelId,
hir::{BindingAnnotation, BindingId, ExprId, ExprOrPatId, PatId}, hir::{BindingAnnotation, BindingId, ExprId, ExprOrPatId, PatId},
lang_item::{LangItem, LangItemTarget}, lang_item::{LangItem, LangItemTarget},
layout::Integer, layout::Integer,

View File

@ -4,16 +4,19 @@
use chalk_ir::{AdtId, TyKind}; use chalk_ir::{AdtId, TyKind};
use hir_def::{ use hir_def::{
layout::{ layout::{
Abi, FieldsShape, Integer, Layout, LayoutCalculator, LayoutError, Primitive, ReprOptions, Abi, FieldsShape, Integer, LayoutCalculator, LayoutS, Primitive, ReprOptions, Scalar, Size,
RustcEnumVariantIdx, Scalar, Size, StructKind, TargetDataLayout, Variants, WrappingRange, StructKind, TargetDataLayout, WrappingRange,
}, },
LocalFieldId, LocalEnumVariantId, LocalFieldId,
}; };
use la_arena::{Idx, RawIdx};
use stdx::never; 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::{ pub use self::{
adt::{layout_of_adt_query, layout_of_adt_recover}, adt::{layout_of_adt_query, layout_of_adt_recover},
target::target_data_layout_query, target::target_data_layout_query,
@ -28,6 +31,34 @@ macro_rules! user_error {
mod adt; mod adt;
mod target; 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> { struct LayoutCx<'a> {
krate: CrateId, krate: CrateId,
target: &'a TargetDataLayout, 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> { 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 Some(target) = db.target_data_layout(krate) else { return Err(LayoutError::TargetLayoutNotAvailable) };
let cx = LayoutCx { krate, target: &target }; let cx = LayoutCx { krate, target: &target };
@ -287,5 +310,13 @@ fn field_ty(
db.field_types(def)[fd].clone().substitute(Interner, subst) 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)] #[cfg(test)]
mod tests; mod tests;

View File

@ -1,16 +1,21 @@
//! Compute the binary representation of structs, unions and enums //! Compute the binary representation of structs, unions and enums
use std::ops::Bound; use std::{cmp, ops::Bound};
use hir_def::{ use hir_def::{
data::adt::VariantData, data::adt::VariantData,
layout::{Integer, IntegerExt, Layout, LayoutCalculator, LayoutError, RustcEnumVariantIdx}, layout::{Integer, LayoutCalculator, ReprOptions, TargetDataLayout},
AdtId, EnumVariantId, HasModule, LocalEnumVariantId, VariantId, AdtId, EnumVariantId, HasModule, LocalEnumVariantId, VariantId,
}; };
use la_arena::RawIdx; use la_arena::RawIdx;
use smallvec::SmallVec; 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}; use super::{layout_of_ty, LayoutCx};
@ -73,7 +78,7 @@ pub fn layout_of_adt_query(
is_enum, is_enum,
is_unsafe_cell(db, def), is_unsafe_cell(db, def),
layout_scalar_valid_range(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, _)| { variants.iter_enumerated().filter_map(|(id, _)| {
let AdtId::EnumId(e) = def else { return None }; let AdtId::EnumId(e) = def else { return None };
let d = let d =
@ -125,3 +130,50 @@ pub fn layout_of_adt_recover(
) -> Result<Layout, LayoutError> { ) -> Result<Layout, LayoutError> {
user_error!("infinite sized recursive type"); 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)
})
}

View File

@ -2,12 +2,14 @@
use base_db::fixture::WithFixture; use base_db::fixture::WithFixture;
use chalk_ir::{AdtId, TyKind}; use chalk_ir::{AdtId, TyKind};
use hir_def::{ use hir_def::db::DefDatabase;
db::DefDatabase,
layout::{Layout, LayoutError},
};
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; use super::layout_of_ty;

View File

@ -10,7 +10,7 @@
use hir_def::{ use hir_def::{
builtin_type::BuiltinType, builtin_type::BuiltinType,
lang_item::{lang_attr, LangItem}, lang_item::{lang_attr, LangItem},
layout::{Layout, LayoutError, RustcEnumVariantIdx, TagEncoding, Variants}, layout::{TagEncoding, Variants},
AdtId, DefWithBodyId, EnumVariantId, FunctionId, HasModule, ItemContainerId, Lookup, VariantId, AdtId, DefWithBodyId, EnumVariantId, FunctionId, HasModule, ItemContainerId, Lookup, VariantId,
}; };
use intern::Interned; use intern::Interned;
@ -21,7 +21,7 @@
db::HirDatabase, db::HirDatabase,
from_placeholder_idx, from_placeholder_idx,
infer::{normalize, PointerCast}, infer::{normalize, PointerCast},
layout::layout_of_ty, layout::{layout_of_ty, Layout, LayoutError, RustcEnumVariantIdx},
mapping::from_chalk, mapping::from_chalk,
method_resolution::{is_dyn_method, lookup_impl_method}, method_resolution::{is_dyn_method, lookup_impl_method},
traits::FnTrait, traits::FnTrait,

View File

@ -11,7 +11,6 @@
RecordFieldPat, RecordLitField, RecordFieldPat, RecordLitField,
}, },
lang_item::{LangItem, LangItemTarget}, lang_item::{LangItem, LangItemTarget},
layout::LayoutError,
path::Path, path::Path,
resolver::{resolver_for_expr, ResolveValueResult, ValueNs}, resolver::{resolver_for_expr, ResolveValueResult, ValueNs},
AdtId, DefWithBodyId, EnumVariantId, HasModule, ItemContainerId, LocalFieldId, TraitId, AdtId, DefWithBodyId, EnumVariantId, HasModule, ItemContainerId, LocalFieldId, TraitId,
@ -26,7 +25,7 @@
display::HirDisplay, display::HirDisplay,
infer::{CaptureKind, CapturedItem, TypeMismatch}, infer::{CaptureKind, CapturedItem, TypeMismatch},
inhabitedness::is_ty_uninhabited_from, inhabitedness::is_ty_uninhabited_from,
layout::layout_of_ty, layout::{layout_of_ty, LayoutError},
mapping::ToChalk, mapping::ToChalk,
static_lifetime, static_lifetime,
utils::generics, utils::generics,

View File

@ -45,7 +45,7 @@
hir::{BindingAnnotation, BindingId, ExprOrPatId, LabelId, Pat}, hir::{BindingAnnotation, BindingId, ExprOrPatId, LabelId, Pat},
item_tree::ItemTreeNode, item_tree::ItemTreeNode,
lang_item::{LangItem, LangItemTarget}, lang_item::{LangItem, LangItemTarget},
layout::{Layout, LayoutError, ReprOptions}, layout::ReprOptions,
nameres::{self, diagnostics::DefDiagnostic, ModuleOrigin}, nameres::{self, diagnostics::DefDiagnostic, ModuleOrigin},
per_ns::PerNs, per_ns::PerNs,
resolver::{HasResolver, Resolver}, resolver::{HasResolver, Resolver},
@ -61,7 +61,7 @@
consteval::{try_const_usize, unknown_const_as_generic, ConstEvalError, ConstExt}, consteval::{try_const_usize, unknown_const_as_generic, ConstEvalError, ConstExt},
diagnostics::BodyValidationDiagnostic, diagnostics::BodyValidationDiagnostic,
display::HexifiedConst, display::HexifiedConst,
layout::layout_of_ty, layout::{layout_of_ty, Layout, LayoutError},
method_resolution::{self, TyFingerprint}, method_resolution::{self, TyFingerprint},
mir::{self, interpret_mir}, mir::{self, interpret_mir},
primitive::UintTy, primitive::UintTy,