forked from M-Labs/nac3
nac3core: option type codegen support
This commit is contained in:
parent
06fcbff876
commit
d86a75bf0e
@ -138,6 +138,7 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> {
|
||||
&mut self.unifier,
|
||||
self.top_level,
|
||||
&mut self.type_cache,
|
||||
&self.primitives,
|
||||
ty,
|
||||
)
|
||||
}
|
||||
@ -199,6 +200,22 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> {
|
||||
val
|
||||
}
|
||||
}
|
||||
Constant::None => {
|
||||
match (
|
||||
self.unifier.get_ty(ty).as_ref(),
|
||||
self.unifier.get_ty(self.primitives.option).as_ref(),
|
||||
) {
|
||||
(
|
||||
TypeEnum::TObj { obj_id, params, .. },
|
||||
TypeEnum::TObj { obj_id: opt_id, .. },
|
||||
) if *obj_id == *opt_id => self
|
||||
.get_llvm_type(generator, *params.iter().next().unwrap().1)
|
||||
.ptr_type(AddressSpace::Generic)
|
||||
.const_null()
|
||||
.into(),
|
||||
_ => unreachable!("must be option type"),
|
||||
}
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
@ -259,6 +259,7 @@ fn get_llvm_type<'ctx>(
|
||||
unifier: &mut Unifier,
|
||||
top_level: &TopLevelContext,
|
||||
type_cache: &mut HashMap<Type, BasicTypeEnum<'ctx>>,
|
||||
primitives: &PrimitiveStore,
|
||||
ty: Type,
|
||||
) -> BasicTypeEnum<'ctx> {
|
||||
use TypeEnum::*;
|
||||
@ -268,9 +269,28 @@ fn get_llvm_type<'ctx>(
|
||||
let ty_enum = unifier.get_ty(ty);
|
||||
let result = match &*ty_enum {
|
||||
TObj { obj_id, fields, .. } => {
|
||||
// check to avoid treating primitives as classes
|
||||
if obj_id.0 <= 7 {
|
||||
unreachable!();
|
||||
// check to avoid treating primitives other than Option as classes
|
||||
if obj_id.0 <= 14 {
|
||||
match (unifier.get_ty(ty).as_ref(), unifier.get_ty(primitives.option).as_ref())
|
||||
{
|
||||
(
|
||||
TypeEnum::TObj { obj_id, params, .. },
|
||||
TypeEnum::TObj { obj_id: opt_id, .. },
|
||||
) if *obj_id == *opt_id => {
|
||||
return get_llvm_type(
|
||||
ctx,
|
||||
generator,
|
||||
unifier,
|
||||
top_level,
|
||||
type_cache,
|
||||
primitives,
|
||||
*params.iter().next().unwrap().1,
|
||||
)
|
||||
.ptr_type(AddressSpace::Generic)
|
||||
.into();
|
||||
}
|
||||
_ => unreachable!("must be option type"),
|
||||
}
|
||||
}
|
||||
// a struct with fields in the order of declaration
|
||||
let top_level_defs = top_level.definitions.read();
|
||||
@ -289,6 +309,7 @@ fn get_llvm_type<'ctx>(
|
||||
unifier,
|
||||
top_level,
|
||||
type_cache,
|
||||
primitives,
|
||||
fields[&f.0].0,
|
||||
)
|
||||
})
|
||||
@ -304,14 +325,14 @@ fn get_llvm_type<'ctx>(
|
||||
// a struct with fields in the order present in the tuple
|
||||
let fields = ty
|
||||
.iter()
|
||||
.map(|ty| get_llvm_type(ctx, generator, unifier, top_level, type_cache, *ty))
|
||||
.map(|ty| get_llvm_type(ctx, generator, unifier, top_level, type_cache, primitives, *ty))
|
||||
.collect_vec();
|
||||
ctx.struct_type(&fields, false).into()
|
||||
}
|
||||
TList { ty } => {
|
||||
// a struct with an integer and a pointer to an array
|
||||
let element_type =
|
||||
get_llvm_type(ctx, generator, unifier, top_level, type_cache, *ty);
|
||||
get_llvm_type(ctx, generator, unifier, top_level, type_cache, primitives, *ty);
|
||||
let fields = [
|
||||
element_type.ptr_type(AddressSpace::Generic).into(),
|
||||
generator.get_size_type(ctx).into(),
|
||||
@ -417,7 +438,8 @@ pub fn gen_func<'ctx, G: CodeGenerator>(
|
||||
exception.set_body(&fields, false);
|
||||
exception.ptr_type(AddressSpace::Generic).into()
|
||||
});
|
||||
// TODO: insert option type cache
|
||||
// NOTE: special handling of option cannot use this type cache since it contains type var,
|
||||
// handled inside get_llvm_type instead
|
||||
|
||||
let (args, ret) = if let ConcreteTypeEnum::TFunc { args, ret, .. } =
|
||||
task.store.get(task.signature)
|
||||
@ -438,7 +460,7 @@ pub fn gen_func<'ctx, G: CodeGenerator>(
|
||||
let ret_type = if unifier.unioned(ret, primitives.none) {
|
||||
None
|
||||
} else {
|
||||
Some(get_llvm_type(context, generator, &mut unifier, top_level_ctx.as_ref(), &mut type_cache, ret))
|
||||
Some(get_llvm_type(context, generator, &mut unifier, top_level_ctx.as_ref(), &mut type_cache, &primitives, ret))
|
||||
};
|
||||
|
||||
let has_sret = ret_type.map_or(false, |ty| need_sret(context, ty));
|
||||
@ -451,6 +473,7 @@ pub fn gen_func<'ctx, G: CodeGenerator>(
|
||||
&mut unifier,
|
||||
top_level_ctx.as_ref(),
|
||||
&mut type_cache,
|
||||
&primitives,
|
||||
arg.ty,
|
||||
)
|
||||
.into()
|
||||
@ -498,6 +521,7 @@ pub fn gen_func<'ctx, G: CodeGenerator>(
|
||||
&mut unifier,
|
||||
top_level_ctx.as_ref(),
|
||||
&mut type_cache,
|
||||
&primitives,
|
||||
arg.ty,
|
||||
),
|
||||
&arg.name.to_string(),
|
||||
|
@ -105,7 +105,7 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
|
||||
("__param2__".into(), int64, true),
|
||||
];
|
||||
|
||||
// for option type
|
||||
// for Option, is_some and is_none share the same type
|
||||
let (is_some_ty, unwrap_ty, (option_ty_var, option_ty_var_id)) =
|
||||
if let TypeEnum::TObj { fields, params, .. } =
|
||||
primitives.1.get_ty(primitives.0.option).as_ref()
|
||||
@ -222,9 +222,33 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
|
||||
instance_to_stmt: Default::default(),
|
||||
resolver: None,
|
||||
codegen_callback: Some(Arc::new(GenCall::new(Box::new(
|
||||
|ctx, _, fun, args, generator| {
|
||||
// TODO:
|
||||
unimplemented!()
|
||||
|ctx, obj, _, _, generator| {
|
||||
let obj_val = obj.unwrap().1.clone().to_basic_value_enum(ctx, generator)?;
|
||||
if let BasicValueEnum::PointerValue(ptr) = obj_val {
|
||||
Ok(Some(ctx.builder.build_is_not_null(ptr, "is_some").into()))
|
||||
} else {
|
||||
unreachable!("option must be ptr")
|
||||
}
|
||||
},
|
||||
)))),
|
||||
loc: None,
|
||||
})),
|
||||
Arc::new(RwLock::new(TopLevelDef::Function {
|
||||
name: "Option.is_none".into(),
|
||||
simple_name: "is_none".into(),
|
||||
signature: is_some_ty.0,
|
||||
var_id: vec![option_ty_var_id],
|
||||
instance_to_symbol: Default::default(),
|
||||
instance_to_stmt: Default::default(),
|
||||
resolver: None,
|
||||
codegen_callback: Some(Arc::new(GenCall::new(Box::new(
|
||||
|ctx, obj, _, _, generator| {
|
||||
let obj_val = obj.unwrap().1.clone().to_basic_value_enum(ctx, generator)?;
|
||||
if let BasicValueEnum::PointerValue(ptr) = obj_val {
|
||||
Ok(Some(ctx.builder.build_is_null(ptr, "is_none").into()))
|
||||
} else {
|
||||
unreachable!("option must be ptr")
|
||||
}
|
||||
},
|
||||
)))),
|
||||
loc: None,
|
||||
@ -238,9 +262,13 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
|
||||
instance_to_stmt: Default::default(),
|
||||
resolver: None,
|
||||
codegen_callback: Some(Arc::new(GenCall::new(Box::new(
|
||||
|ctx, _, fun, args, generator| {
|
||||
// TODO:
|
||||
unimplemented!()
|
||||
|ctx, obj, _, _, generator| {
|
||||
let obj_val = obj.unwrap().1.clone().to_basic_value_enum(ctx, generator)?;
|
||||
if let BasicValueEnum::PointerValue(ptr) = obj_val {
|
||||
Ok(Some(ctx.builder.build_load(ptr, "unwrap_some")))
|
||||
} else {
|
||||
unreachable!("option must be ptr")
|
||||
}
|
||||
},
|
||||
)))),
|
||||
loc: None,
|
||||
@ -1176,8 +1204,11 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
|
||||
instance_to_stmt: Default::default(),
|
||||
resolver: None,
|
||||
codegen_callback: Some(Arc::new(GenCall::new(Box::new(
|
||||
|ctx, _, fun, args, generator| {
|
||||
unimplemented!()
|
||||
|ctx, _, _fun, args, generator| {
|
||||
let arg_val = args[0].1.clone().to_basic_value_enum(ctx, generator)?;
|
||||
let alloca = ctx.builder.build_alloca(arg_val.get_type(), "alloca_some");
|
||||
ctx.builder.build_store(alloca, arg_val);
|
||||
Ok(Some(alloca.into()))
|
||||
},
|
||||
)))),
|
||||
loc: None,
|
||||
|
@ -123,6 +123,7 @@ impl TopLevelComposer {
|
||||
obj_id: DefinitionId(10),
|
||||
fields: vec![
|
||||
("is_some".into(), (is_some_type_fun_ty, true)),
|
||||
("is_none".into(), (is_some_type_fun_ty, true)),
|
||||
("unwrap".into(), (unwrap_fun_ty, true)),
|
||||
]
|
||||
.into_iter()
|
||||
|
Loading…
Reference in New Issue
Block a user