use std::sync::Arc;
use super::context::*;
use super::ty::*;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum BuiltinTraitId {
Copy,
Clone,
Sized,
Send,
Sync,
Drop,
Default,
Debug,
Display,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
Iterator,
IntoIterator,
FromIterator,
Add,
Sub,
Mul,
Div,
Rem,
Neg,
Not,
Index,
IndexMut,
Deref,
DerefMut,
Fn,
FnMut,
FnOnce,
Future,
Try,
From,
Into,
AsRef,
AsMut,
}
pub struct Builtins {
trait_ids: std::collections::HashMap<BuiltinTraitId, DefId>,
}
impl Builtins {
pub fn new(ctx: &mut TypeContext) -> Self {
let mut builtins = Self {
trait_ids: std::collections::HashMap::new(),
};
builtins.register_traits(ctx);
builtins.register_primitive_impls(ctx);
builtins
}
pub fn trait_id(&self, id: BuiltinTraitId) -> Option<DefId> {
self.trait_ids.get(&id).copied()
}
fn register_traits(&mut self, ctx: &mut TypeContext) {
self.register_trait(ctx, BuiltinTraitId::Copy, "Copy", vec![]);
self.register_trait(ctx, BuiltinTraitId::Clone, "Clone", vec![]);
self.register_trait(ctx, BuiltinTraitId::Sized, "Sized", vec![]);
self.register_trait(ctx, BuiltinTraitId::Send, "Send", vec![]);
self.register_trait(ctx, BuiltinTraitId::Sync, "Sync", vec![]);
self.register_trait(ctx, BuiltinTraitId::Drop, "Drop", vec![]);
self.register_trait(ctx, BuiltinTraitId::Default, "Default", vec![]);
self.register_trait(ctx, BuiltinTraitId::Debug, "Debug", vec![]);
self.register_trait(ctx, BuiltinTraitId::Display, "Display", vec![]);
self.register_trait(ctx, BuiltinTraitId::PartialEq, "PartialEq", vec![]);
self.register_trait(
ctx,
BuiltinTraitId::Eq,
"Eq",
vec![BuiltinTraitId::PartialEq],
);
self.register_trait(
ctx,
BuiltinTraitId::PartialOrd,
"PartialOrd",
vec![BuiltinTraitId::PartialEq],
);
self.register_trait(
ctx,
BuiltinTraitId::Ord,
"Ord",
vec![BuiltinTraitId::Eq, BuiltinTraitId::PartialOrd],
);
self.register_trait(ctx, BuiltinTraitId::Hash, "Hash", vec![]);
self.register_trait(ctx, BuiltinTraitId::Iterator, "Iterator", vec![]);
self.register_trait(ctx, BuiltinTraitId::IntoIterator, "IntoIterator", vec![]);
self.register_trait(ctx, BuiltinTraitId::FromIterator, "FromIterator", vec![]);
self.register_trait(ctx, BuiltinTraitId::Add, "Add", vec![]);
self.register_trait(ctx, BuiltinTraitId::Sub, "Sub", vec![]);
self.register_trait(ctx, BuiltinTraitId::Mul, "Mul", vec![]);
self.register_trait(ctx, BuiltinTraitId::Div, "Div", vec![]);
self.register_trait(ctx, BuiltinTraitId::Rem, "Rem", vec![]);
self.register_trait(ctx, BuiltinTraitId::Neg, "Neg", vec![]);
self.register_trait(ctx, BuiltinTraitId::Not, "Not", vec![]);
self.register_trait(ctx, BuiltinTraitId::Index, "Index", vec![]);
self.register_trait(
ctx,
BuiltinTraitId::IndexMut,
"IndexMut",
vec![BuiltinTraitId::Index],
);
self.register_trait(ctx, BuiltinTraitId::Deref, "Deref", vec![]);
self.register_trait(
ctx,
BuiltinTraitId::DerefMut,
"DerefMut",
vec![BuiltinTraitId::Deref],
);
self.register_trait(ctx, BuiltinTraitId::FnOnce, "FnOnce", vec![]);
self.register_trait(
ctx,
BuiltinTraitId::FnMut,
"FnMut",
vec![BuiltinTraitId::FnOnce],
);
self.register_trait(ctx, BuiltinTraitId::Fn, "Fn", vec![BuiltinTraitId::FnMut]);
self.register_trait(ctx, BuiltinTraitId::Future, "Future", vec![]);
self.register_trait(ctx, BuiltinTraitId::Try, "Try", vec![]);
self.register_trait(ctx, BuiltinTraitId::From, "From", vec![]);
self.register_trait(ctx, BuiltinTraitId::Into, "Into", vec![]);
self.register_trait(ctx, BuiltinTraitId::AsRef, "AsRef", vec![]);
self.register_trait(ctx, BuiltinTraitId::AsMut, "AsMut", vec![]);
}
fn register_trait(
&mut self,
ctx: &mut TypeContext,
id: BuiltinTraitId,
name: &str,
supertraits: Vec<BuiltinTraitId>,
) {
let def_id = ctx.fresh_def_id();
self.trait_ids.insert(id, def_id);
let supertrait_bounds: Vec<_> = supertraits
.iter()
.filter_map(|st| {
self.trait_ids.get(st).map(|&trait_id| TraitBound {
trait_id,
args: Vec::new(),
})
})
.collect();
let trait_def = TraitDef {
def_id,
name: Arc::from(name),
generics: Vec::new(),
supertraits: supertrait_bounds,
assoc_types: Vec::new(),
methods: Vec::new(),
};
ctx.register_trait(trait_def);
}
fn register_primitive_impls(&mut self, ctx: &mut TypeContext) {
let copy_clone_traits = vec![
BuiltinTraitId::Copy,
BuiltinTraitId::Clone,
BuiltinTraitId::Sized,
BuiltinTraitId::Send,
BuiltinTraitId::Sync,
BuiltinTraitId::Default,
BuiltinTraitId::Debug,
BuiltinTraitId::PartialEq,
BuiltinTraitId::Eq,
BuiltinTraitId::PartialOrd,
BuiltinTraitId::Ord,
BuiltinTraitId::Hash,
];
let int_types = vec![
Ty::int(IntTy::I8),
Ty::int(IntTy::I16),
Ty::int(IntTy::I32),
Ty::int(IntTy::I64),
Ty::int(IntTy::I128),
Ty::int(IntTy::Isize),
Ty::int(IntTy::U8),
Ty::int(IntTy::U16),
Ty::int(IntTy::U32),
Ty::int(IntTy::U64),
Ty::int(IntTy::U128),
Ty::int(IntTy::Usize),
];
for ty in &int_types {
for trait_id in ©_clone_traits {
self.register_impl(ctx, *trait_id, ty.clone());
}
self.register_impl(ctx, BuiltinTraitId::Add, ty.clone());
self.register_impl(ctx, BuiltinTraitId::Sub, ty.clone());
self.register_impl(ctx, BuiltinTraitId::Mul, ty.clone());
self.register_impl(ctx, BuiltinTraitId::Div, ty.clone());
self.register_impl(ctx, BuiltinTraitId::Rem, ty.clone());
}
let signed_int_types = vec![
Ty::int(IntTy::I8),
Ty::int(IntTy::I16),
Ty::int(IntTy::I32),
Ty::int(IntTy::I64),
Ty::int(IntTy::I128),
Ty::int(IntTy::Isize),
];
for ty in &signed_int_types {
self.register_impl(ctx, BuiltinTraitId::Neg, ty.clone());
}
let float_types = vec![Ty::float(FloatTy::F32), Ty::float(FloatTy::F64)];
for ty in &float_types {
self.register_impl(ctx, BuiltinTraitId::Copy, ty.clone());
self.register_impl(ctx, BuiltinTraitId::Clone, ty.clone());
self.register_impl(ctx, BuiltinTraitId::Sized, ty.clone());
self.register_impl(ctx, BuiltinTraitId::Send, ty.clone());
self.register_impl(ctx, BuiltinTraitId::Sync, ty.clone());
self.register_impl(ctx, BuiltinTraitId::Default, ty.clone());
self.register_impl(ctx, BuiltinTraitId::Debug, ty.clone());
self.register_impl(ctx, BuiltinTraitId::PartialEq, ty.clone());
self.register_impl(ctx, BuiltinTraitId::PartialOrd, ty.clone());
self.register_impl(ctx, BuiltinTraitId::Add, ty.clone());
self.register_impl(ctx, BuiltinTraitId::Sub, ty.clone());
self.register_impl(ctx, BuiltinTraitId::Mul, ty.clone());
self.register_impl(ctx, BuiltinTraitId::Div, ty.clone());
self.register_impl(ctx, BuiltinTraitId::Rem, ty.clone());
self.register_impl(ctx, BuiltinTraitId::Neg, ty.clone());
}
let bool_ty = Ty::bool();
for trait_id in ©_clone_traits {
self.register_impl(ctx, *trait_id, bool_ty.clone());
}
self.register_impl(ctx, BuiltinTraitId::Not, bool_ty.clone());
self.register_impl(ctx, BuiltinTraitId::Display, bool_ty.clone());
let char_ty = Ty::char();
for trait_id in ©_clone_traits {
self.register_impl(ctx, *trait_id, char_ty.clone());
}
self.register_impl(ctx, BuiltinTraitId::Display, char_ty.clone());
let unit_ty = Ty::unit();
self.register_impl(ctx, BuiltinTraitId::Copy, unit_ty.clone());
self.register_impl(ctx, BuiltinTraitId::Clone, unit_ty.clone());
self.register_impl(ctx, BuiltinTraitId::Sized, unit_ty.clone());
self.register_impl(ctx, BuiltinTraitId::Send, unit_ty.clone());
self.register_impl(ctx, BuiltinTraitId::Sync, unit_ty.clone());
self.register_impl(ctx, BuiltinTraitId::Default, unit_ty.clone());
self.register_impl(ctx, BuiltinTraitId::Debug, unit_ty.clone());
self.register_impl(ctx, BuiltinTraitId::PartialEq, unit_ty.clone());
self.register_impl(ctx, BuiltinTraitId::Eq, unit_ty.clone());
self.register_impl(ctx, BuiltinTraitId::PartialOrd, unit_ty.clone());
self.register_impl(ctx, BuiltinTraitId::Ord, unit_ty.clone());
self.register_impl(ctx, BuiltinTraitId::Hash, unit_ty.clone());
let never_ty = Ty::never();
self.register_impl(ctx, BuiltinTraitId::Sized, never_ty.clone());
}
fn register_impl(&mut self, ctx: &mut TypeContext, trait_id: BuiltinTraitId, self_ty: Ty) {
if let Some(&def_id) = self.trait_ids.get(&trait_id) {
let impl_ = TraitImpl {
trait_id: def_id,
self_ty,
generics: Vec::new(),
assoc_types: std::collections::HashMap::new(),
methods: std::collections::HashMap::new(),
where_clauses: Vec::new(),
};
ctx.register_impl(impl_);
}
}
}
pub fn is_copy(ctx: &TypeContext, builtins: &Builtins, ty: &Ty) -> bool {
if let Some(copy_id) = builtins.trait_id(BuiltinTraitId::Copy) {
!ctx.find_impls(copy_id, ty).is_empty()
} else {
matches!(
ty.kind,
TyKind::Int(_)
| TyKind::Float(_)
| TyKind::Bool
| TyKind::Char
| TyKind::Ptr(_, _)
| TyKind::Never
)
}
}
pub fn is_sized(ty: &Ty) -> bool {
!matches!(ty.kind, TyKind::Slice(_) | TyKind::Str)
}
pub fn is_send(ctx: &TypeContext, builtins: &Builtins, ty: &Ty) -> bool {
if let Some(send_id) = builtins.trait_id(BuiltinTraitId::Send) {
!ctx.find_impls(send_id, ty).is_empty()
} else {
true
}
}
pub fn is_sync(ctx: &TypeContext, builtins: &Builtins, ty: &Ty) -> bool {
if let Some(sync_id) = builtins.trait_id(BuiltinTraitId::Sync) {
!ctx.find_impls(sync_id, ty).is_empty()
} else {
true
}
}
pub fn default_value_repr(ty: &Ty) -> Option<String> {
match &ty.kind {
TyKind::Int(int_ty) => Some(match int_ty {
IntTy::I8
| IntTy::I16
| IntTy::I32
| IntTy::I64
| IntTy::I128
| IntTy::Isize
| IntTy::U8
| IntTy::U16
| IntTy::U32
| IntTy::U64
| IntTy::U128
| IntTy::Usize => "0".to_string(),
}),
TyKind::Float(_) => Some("0.0".to_string()),
TyKind::Bool => Some("false".to_string()),
TyKind::Char => Some("'\\0'".to_string()),
TyKind::Tuple(elems) if elems.is_empty() => Some("()".to_string()),
_ => None,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_builtins_registration() {
let mut ctx = TypeContext::new();
let builtins = Builtins::new(&mut ctx);
assert!(builtins.trait_id(BuiltinTraitId::Copy).is_some());
let i32_ty = Ty::int(IntTy::I32);
assert!(is_copy(&ctx, &builtins, &i32_ty));
}
#[test]
fn test_is_sized() {
assert!(is_sized(&Ty::int(IntTy::I32)));
assert!(is_sized(&Ty::bool()));
assert!(!is_sized(&Ty::str()));
assert!(!is_sized(&Ty::slice(Ty::int(IntTy::U8))));
}
#[test]
fn test_default_values() {
assert_eq!(
default_value_repr(&Ty::int(IntTy::I32)),
Some("0".to_string())
);
assert_eq!(default_value_repr(&Ty::bool()), Some("false".to_string()));
assert_eq!(
default_value_repr(&Ty::float(FloatTy::F64)),
Some("0.0".to_string())
);
}
}