use rustc crates instead of copy paste

This commit is contained in:
hkalbasi 2022-12-07 01:59:38 +03:30
parent f2c9502185
commit 05906da0ec
13 changed files with 291 additions and 2083 deletions

View file

@ -19,10 +19,11 @@ use std::sync::Arc;
use chalk_ir::{cast::Cast, ConstValue, DebruijnIndex, Mutability, Safety, Scalar, TypeFlags};
use hir_def::{
body::Body,
builtin_type::BuiltinType,
builtin_type::{BuiltinInt, BuiltinType, BuiltinUint},
data::{ConstData, StaticData},
expr::{BindingAnnotation, ExprId, PatId},
lang_item::LangItemTarget,
layout::Integer,
path::{path, Path},
resolver::{HasResolver, ResolveValueResult, Resolver, TypeNs, ValueNs},
type_ref::TypeRef,
@ -70,8 +71,26 @@ pub(crate) fn infer_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc<Infer
DefWithBodyId::StaticId(s) => ctx.collect_static(&db.static_data(s)),
DefWithBodyId::VariantId(v) => {
ctx.return_ty = TyBuilder::builtin(match db.enum_data(v.parent).variant_body_type() {
Either::Left(builtin) => BuiltinType::Int(builtin),
Either::Right(builtin) => BuiltinType::Uint(builtin),
hir_def::layout::IntegerType::Pointer(signed) => match signed {
true => BuiltinType::Int(BuiltinInt::Isize),
false => BuiltinType::Uint(BuiltinUint::Usize),
},
hir_def::layout::IntegerType::Fixed(size, signed) => match signed {
true => BuiltinType::Int(match size {
Integer::I8 => BuiltinInt::I8,
Integer::I16 => BuiltinInt::I16,
Integer::I32 => BuiltinInt::I32,
Integer::I64 => BuiltinInt::I64,
Integer::I128 => BuiltinInt::I128,
}),
false => BuiltinType::Uint(match size {
Integer::I8 => BuiltinUint::U8,
Integer::I16 => BuiltinUint::U16,
Integer::I32 => BuiltinUint::U32,
Integer::I64 => BuiltinUint::U64,
Integer::I128 => BuiltinUint::U128,
}),
},
});
}
}

View file

@ -1,12 +1,15 @@
//! Compute the binary representation of a type
use std::sync::Arc;
use chalk_ir::{AdtId, TyKind};
pub(self) use hir_def::layout::*;
use hir_def::LocalFieldId;
use stdx::never;
use crate::{db::HirDatabase, Interner, Substitution, Ty};
use self::adt::univariant;
use self::adt::struct_variant_idx;
pub use self::{
adt::{layout_of_adt_query, layout_of_adt_recover},
target::current_target_data_layout_query,
@ -21,6 +24,22 @@ macro_rules! user_error {
mod adt;
mod target;
struct LayoutCx<'a> {
db: &'a dyn HirDatabase,
}
impl LayoutCalculator for LayoutCx<'_> {
type TargetDataLayoutRef = Arc<TargetDataLayout>;
fn delay_bug(&self, txt: &str) {
never!("{}", txt);
}
fn current_data_layout(&self) -> Arc<TargetDataLayout> {
self.db.current_target_data_layout()
}
}
fn scalar_unit(dl: &TargetDataLayout, value: Primitive) -> Scalar {
Scalar::Initialized { value, valid_range: WrappingRange::full(value.size(dl)) }
}
@ -29,34 +48,9 @@ fn scalar(dl: &TargetDataLayout, value: Primitive) -> Layout {
Layout::scalar(dl, scalar_unit(dl, value))
}
fn scalar_pair(dl: &TargetDataLayout, a: Scalar, b: Scalar) -> Layout {
let b_align = b.align(dl);
let align = a.align(dl).max(b_align).max(dl.aggregate_align);
let b_offset = a.size(dl).align_to(b_align.abi);
let size = b_offset.checked_add(b.size(dl), dl).unwrap().align_to(align.abi);
// HACK(nox): We iter on `b` and then `a` because `max_by_key`
// returns the last maximum.
let largest_niche = Niche::from_scalar(dl, b_offset, b)
.into_iter()
.chain(Niche::from_scalar(dl, Size::ZERO, a))
.max_by_key(|niche| niche.available(dl));
Layout {
variants: Variants::Single,
fields: FieldsShape::Arbitrary {
offsets: vec![Size::ZERO, b_offset],
memory_index: vec![0, 1],
},
abi: Abi::ScalarPair(a, b),
largest_niche,
align,
size,
}
}
pub fn layout_of_ty(db: &dyn HirDatabase, ty: &Ty) -> Result<Layout, LayoutError> {
let dl = &*db.current_target_data_layout();
let cx = LayoutCx { db };
Ok(match ty.kind(Interner) {
TyKind::Adt(AdtId(def), subst) => db.layout_of_adt(*def, subst.clone())?,
TyKind::Scalar(s) => match s {
@ -113,14 +107,13 @@ pub fn layout_of_ty(db: &dyn HirDatabase, ty: &Ty) -> Result<Layout, LayoutError
TyKind::Tuple(len, tys) => {
let kind = if *len == 0 { StructKind::AlwaysSized } else { StructKind::MaybeUnsized };
univariant(
dl,
&tys.iter(Interner)
.map(|k| layout_of_ty(db, k.assert_ty_ref(Interner)))
.collect::<Result<Vec<_>, _>>()?,
&ReprOptions::default(),
kind,
)?
let fields = tys
.iter(Interner)
.map(|k| layout_of_ty(db, k.assert_ty_ref(Interner)))
.collect::<Result<Vec<_>, _>>()?;
let fields = fields.iter().collect::<Vec<_>>();
let fields = fields.iter().collect::<Vec<_>>();
cx.univariant(dl, &fields, &ReprOptions::default(), kind).ok_or(LayoutError::Unknown)?
}
TyKind::Array(element, count) => {
let count = match count.data(Interner).value {
@ -146,7 +139,7 @@ pub fn layout_of_ty(db: &dyn HirDatabase, ty: &Ty) -> Result<Layout, LayoutError
let largest_niche = if count != 0 { element.largest_niche } else { None };
Layout {
variants: Variants::Single,
variants: Variants::Single { index: struct_variant_idx() },
fields: FieldsShape::Array { stride: element.size, count },
abi,
largest_niche,
@ -157,7 +150,7 @@ pub fn layout_of_ty(db: &dyn HirDatabase, ty: &Ty) -> Result<Layout, LayoutError
TyKind::Slice(element) => {
let element = layout_of_ty(db, element)?;
Layout {
variants: Variants::Single,
variants: Variants::Single { index: struct_variant_idx() },
fields: FieldsShape::Array { stride: element.size, count: 0 },
abi: Abi::Aggregate { sized: false },
largest_niche: None,
@ -194,13 +187,11 @@ pub fn layout_of_ty(db: &dyn HirDatabase, ty: &Ty) -> Result<Layout, LayoutError
};
// Effectively a (ptr, meta) tuple.
scalar_pair(dl, data_ptr, metadata)
}
TyKind::FnDef(_, _) => {
univariant(dl, &[], &ReprOptions::default(), StructKind::AlwaysSized)?
cx.scalar_pair(data_ptr, metadata)
}
TyKind::FnDef(_, _) => layout_of_unit(&cx, dl)?,
TyKind::Str => Layout {
variants: Variants::Single,
variants: Variants::Single { index: struct_variant_idx() },
fields: FieldsShape::Array { stride: Size::from_bytes(1), count: 0 },
abi: Abi::Aggregate { sized: false },
largest_niche: None,
@ -208,7 +199,7 @@ pub fn layout_of_ty(db: &dyn HirDatabase, ty: &Ty) -> Result<Layout, LayoutError
size: Size::ZERO,
},
TyKind::Never => Layout {
variants: Variants::Single,
variants: Variants::Single { index: struct_variant_idx() },
fields: FieldsShape::Primitive,
abi: Abi::Uninhabited,
largest_niche: None,
@ -216,7 +207,7 @@ pub fn layout_of_ty(db: &dyn HirDatabase, ty: &Ty) -> Result<Layout, LayoutError
size: Size::ZERO,
},
TyKind::Dyn(_) | TyKind::Foreign(_) => {
let mut unit = univariant(dl, &[], &ReprOptions::default(), StructKind::AlwaysSized)?;
let mut unit = layout_of_unit(&cx, dl)?;
match unit.abi {
Abi::Aggregate { ref mut sized } => *sized = false,
_ => user_error!("bug"),
@ -241,6 +232,16 @@ pub fn layout_of_ty(db: &dyn HirDatabase, ty: &Ty) -> Result<Layout, LayoutError
})
}
fn layout_of_unit(cx: &LayoutCx<'_>, dl: &TargetDataLayout) -> Result<Layout, LayoutError> {
cx.univariant::<RustcEnumVariantIdx, &&Layout>(
&dl,
&[],
&ReprOptions::default(),
StructKind::AlwaysSized,
)
.ok_or(LayoutError::Unknown)
}
fn struct_tail_erasing_lifetimes(db: &dyn HirDatabase, pointee: Ty) -> Ty {
match pointee.kind(Interner) {
TyKind::Adt(AdtId(adt), subst) => match adt {

File diff suppressed because it is too large Load diff

View file

@ -35,7 +35,7 @@ pub fn current_target_data_layout_query(db: &dyn HirDatabase) -> Arc<TargetDataL
f32_align: AbiAndPrefAlign::new(Align::from_bytes(4).unwrap()),
f64_align: AbiAndPrefAlign::new(Align::from_bytes(8).unwrap()),
pointer_size,
pointer_align: AbiAndPrefAlign::new(Align::from_bytes(8).unwrap()),
pointer_align: AbiAndPrefAlign::new(Align::from_bytes(pointer_size.bytes()).unwrap()),
aggregate_align: AbiAndPrefAlign::new(Align::from_bytes(1).unwrap()),
vector_align: vec![],
instruction_address_space: AddressSpace(0),

View file

@ -49,6 +49,17 @@ fn check_fail(ra_fixture: &str, e: LayoutError) {
}
macro_rules! size_and_align {
(minicore: $($x:tt),*;$($t:tt)*) => {
{
#[allow(dead_code)]
$($t)*
check_size_and_align(
&format!("//- minicore: {}\n{}", stringify!($($x),*), stringify!($($t)*)),
::std::mem::size_of::<Goal>() as u64,
::std::mem::align_of::<Goal>() as u64,
);
}
};
($($t:tt)*) => {
{
#[allow(dead_code)]
@ -67,7 +78,6 @@ fn hello_world() {
size_and_align! {
struct Goal(i32);
}
//check_size_and_align(r#"struct Goal(i32)"#, 4, 4);
}
#[test]
@ -148,33 +158,39 @@ fn tuple() {
#[test]
fn non_zero() {
check_size_and_align(
r#"
//- minicore: non_zero, option
use core::num::NonZeroU8;
struct Goal(Option<NonZeroU8>);
"#,
1,
1,
);
size_and_align! {
minicore: non_zero, option;
use core::num::NonZeroU8;
struct Goal(Option<NonZeroU8>);
}
}
#[test]
fn niche_optimization() {
check_size_and_align(
r#"
//- minicore: option
struct Goal(Option<&i32>);
"#,
8,
8,
);
check_size_and_align(
r#"
//- minicore: option
struct Goal(Option<Option<bool>>);
"#,
1,
1,
);
size_and_align! {
minicore: option;
struct Goal(Option<&'static i32>);
}
size_and_align! {
minicore: option;
struct Goal(Option<Option<bool>>);
}
}
#[test]
fn enums_with_discriminants() {
size_and_align! {
enum Goal {
A = 1000,
B = 2000,
C = 3000,
}
}
size_and_align! {
enum Goal {
A = 254,
B,
C, // implicitly becomes 256, so we need two bytes
}
}
}