use std::collections::HashMap;
use rucc_base::{Idx, Symbol};
use crate::kind::{
ArrayLen, EnumId, FloatKind, FunctionId, FunctionType, IntKind, Qualifiers, RecordId,
RecordKind, Type, TypeKind,
};
use crate::layout::Layout;
use crate::record::{Field, RecordLayout};
#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct TypeId(Idx<Entry>);
impl std::fmt::Debug for TypeId {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "TypeId#{}", self.0.raw())
}
}
#[derive(Debug, Clone, Copy)]
struct Entry {
ty: Type,
canonical: TypeId,
}
#[derive(Debug, Clone)]
pub struct RecordInfo {
pub kind: RecordKind,
pub tag: Option<Symbol>,
pub layout: Option<Layout>,
pub fields: Vec<Field>,
}
#[derive(Debug, Clone)]
pub struct EnumInfo {
pub tag: Option<Symbol>,
pub underlying: Option<TypeId>,
pub fixed: bool,
}
#[derive(Debug)]
pub struct Types {
entries: Vec<Entry>,
map: HashMap<Type, TypeId>,
functions: Vec<FunctionType>,
function_map: HashMap<FunctionType, FunctionId>,
records: Vec<RecordInfo>,
enums: Vec<EnumInfo>,
void: TypeId,
boolean: TypeId,
ints: [TypeId; 13],
floats: [TypeId; 9],
}
impl Default for Types {
fn default() -> Types {
Types::new()
}
}
impl Types {
#[must_use]
pub fn new() -> Types {
let mut types = Types {
entries: Vec::new(),
map: HashMap::new(),
functions: Vec::new(),
function_map: HashMap::new(),
records: Vec::new(),
enums: Vec::new(),
void: TypeId(Idx::new(0)),
boolean: TypeId(Idx::new(0)),
ints: [TypeId(Idx::new(0)); 13],
floats: [TypeId(Idx::new(0)); 9],
};
types.void = types.intern(Type::new(TypeKind::Void));
types.boolean = types.intern(Type::new(TypeKind::Bool));
for kind in IntKind::ALL {
types.ints[kind.index()] = types.intern(Type::new(TypeKind::Int(kind)));
}
for kind in FloatKind::ALL {
types.floats[kind.index()] = types.intern(Type::new(TypeKind::Float(kind)));
}
types
}
#[must_use]
pub fn len(&self) -> usize {
self.entries.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.entries.is_empty()
}
#[must_use]
pub fn get(&self, id: TypeId) -> Type {
self.entries[id.0.index()].ty
}
#[must_use]
pub fn kind(&self, id: TypeId) -> TypeKind {
self.get(id).kind
}
#[must_use]
pub fn quals(&self, id: TypeId) -> Qualifiers {
self.get(id).quals
}
#[must_use]
pub fn canonical(&self, id: TypeId) -> TypeId {
self.entries[id.0.index()].canonical
}
#[must_use]
pub fn is_sugar(&self, id: TypeId) -> bool {
self.canonical(id) != id
}
#[must_use]
pub fn void(&self) -> TypeId {
self.void
}
#[must_use]
pub fn boolean(&self) -> TypeId {
self.boolean
}
#[must_use]
pub fn int(&self, kind: IntKind) -> TypeId {
self.ints[kind.index()]
}
#[must_use]
pub fn float(&self, kind: FloatKind) -> TypeId {
self.floats[kind.index()]
}
pub fn complex(&mut self, kind: FloatKind) -> TypeId {
self.intern(Type::new(TypeKind::Complex(kind)))
}
pub fn bit_int(&mut self, signed: bool, width: u32) -> TypeId {
self.intern(Type::new(TypeKind::BitInt { signed, width }))
}
pub fn pointer(&mut self, pointee: TypeId) -> TypeId {
self.intern(Type::new(TypeKind::Pointer(pointee)))
}
pub fn atomic(&mut self, inner: TypeId) -> TypeId {
self.intern(Type::new(TypeKind::Atomic(inner)))
}
pub fn array(&mut self, elem: TypeId, len: ArrayLen) -> TypeId {
self.intern(Type::new(TypeKind::Array { elem, len }))
}
pub fn vector(&mut self, elem: TypeId, len: u32) -> TypeId {
self.intern(Type::new(TypeKind::Vector { elem, len }))
}
pub fn function(&mut self, signature: FunctionType) -> TypeId {
let id = match self.function_map.get(&signature) {
Some(&id) => id,
None => {
let id = FunctionId(u32::try_from(self.functions.len()).expect("too many types"));
self.functions.push(signature.clone());
self.function_map.insert(signature, id);
id
}
};
self.intern(Type::new(TypeKind::Function(id)))
}
#[must_use]
pub fn signature(&self, id: FunctionId) -> &FunctionType {
&self.functions[id.0 as usize]
}
pub fn declare_record(&mut self, kind: RecordKind, tag: Option<Symbol>) -> RecordId {
let id = RecordId(u32::try_from(self.records.len()).expect("too many types"));
self.records.push(RecordInfo { kind, tag, layout: None, fields: Vec::new() });
id
}
pub fn record(&mut self, id: RecordId) -> TypeId {
self.intern(Type::new(TypeKind::Record(id)))
}
#[must_use]
pub fn record_info(&self, id: RecordId) -> &RecordInfo {
&self.records[id.0 as usize]
}
pub fn complete_record(&mut self, id: RecordId, laid_out: RecordLayout) {
let info = &mut self.records[id.0 as usize];
info.layout = Some(laid_out.layout);
info.fields = laid_out.fields;
}
#[must_use]
pub fn field(&self, id: RecordId, name: Symbol) -> Option<&Field> {
self.records[id.0 as usize].fields.iter().find(|field| field.name == Some(name))
}
pub fn declare_enum(&mut self, tag: Option<Symbol>) -> EnumId {
let id = EnumId(u32::try_from(self.enums.len()).expect("too many types"));
self.enums.push(EnumInfo { tag, underlying: None, fixed: false });
id
}
pub fn enumeration(&mut self, id: EnumId) -> TypeId {
self.intern(Type::new(TypeKind::Enum(id)))
}
#[must_use]
pub fn enum_info(&self, id: EnumId) -> &EnumInfo {
&self.enums[id.0 as usize]
}
pub fn complete_enum(&mut self, id: EnumId, underlying: TypeId, fixed: bool) {
let info = &mut self.enums[id.0 as usize];
info.underlying = Some(underlying);
info.fixed = fixed;
}
pub fn typedef(&mut self, name: Symbol, underlying: TypeId) -> TypeId {
self.intern(Type::new(TypeKind::Typedef { name, underlying }))
}
pub fn qualified(&mut self, id: TypeId, quals: Qualifiers) -> TypeId {
if quals.is_none() {
return id;
}
let ty = self.get(id);
if let TypeKind::Array { elem, len } = ty.kind {
let elem = self.qualified(elem, quals);
return self.intern(Type { kind: TypeKind::Array { elem, len }, quals: ty.quals });
}
self.intern(Type { kind: ty.kind, quals: ty.quals.with(quals) })
}
pub fn unqualified(&mut self, id: TypeId) -> TypeId {
let ty = self.get(id);
if ty.quals.is_none() {
return id;
}
self.intern(Type::new(ty.kind))
}
fn intern(&mut self, ty: Type) -> TypeId {
if let Some(&id) = self.map.get(&ty) {
return id;
}
let canonical = self.canonicalise(&ty);
if let Some(&id) = self.map.get(&ty) {
return id;
}
let id = TypeId(Idx::from_usize(self.entries.len()));
self.entries.push(Entry { ty, canonical: canonical.unwrap_or(id) });
self.map.insert(ty, id);
id
}
fn canonicalise(&mut self, ty: &Type) -> Option<TypeId> {
match ty.kind {
TypeKind::Typedef { underlying, .. } => {
let base = self.canonical(underlying);
Some(self.qualified(base, ty.quals))
}
TypeKind::Pointer(inner) => self.rebuild(ty, inner, TypeKind::Pointer),
TypeKind::Atomic(inner) => self.rebuild(ty, inner, TypeKind::Atomic),
TypeKind::Array { elem, len } => {
self.rebuild(ty, elem, |elem| TypeKind::Array { elem, len })
}
TypeKind::Vector { elem, len } => {
self.rebuild(ty, elem, |elem| TypeKind::Vector { elem, len })
}
TypeKind::Function(id) => self.canonicalise_function(ty, id),
TypeKind::Void
| TypeKind::Bool
| TypeKind::Int(_)
| TypeKind::Float(_)
| TypeKind::Complex(_)
| TypeKind::BitInt { .. }
| TypeKind::Record(_)
| TypeKind::Enum(_) => None,
}
}
fn rebuild(
&mut self,
ty: &Type,
inner: TypeId,
make: impl FnOnce(TypeId) -> TypeKind,
) -> Option<TypeId> {
let canonical = self.canonical(inner);
if canonical == inner {
return None;
}
Some(self.intern(Type { kind: make(canonical), quals: ty.quals }))
}
fn canonicalise_function(&mut self, ty: &Type, id: FunctionId) -> Option<TypeId> {
let signature = self.signature(id).clone();
let ret = self.canonical(signature.ret);
let params: Vec<TypeId> =
signature.params.iter().map(|¶m| self.canonical(param)).collect();
if ret == signature.ret && params == signature.params {
return None;
}
let canonical = FunctionType { ret, params, ..signature };
let id = self.function(canonical);
Some(self.qualified(id, ty.quals))
}
}