forked from M-Labs/nac3
nac3core: option type codegen support
This commit is contained in:
parent
925f1c2cc4
commit
34b460757b
@ -138,6 +138,7 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> {
|
|||||||
&mut self.unifier,
|
&mut self.unifier,
|
||||||
self.top_level,
|
self.top_level,
|
||||||
&mut self.type_cache,
|
&mut self.type_cache,
|
||||||
|
&self.primitives,
|
||||||
ty,
|
ty,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -199,6 +200,22 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> {
|
|||||||
val
|
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!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -259,6 +259,7 @@ fn get_llvm_type<'ctx>(
|
|||||||
unifier: &mut Unifier,
|
unifier: &mut Unifier,
|
||||||
top_level: &TopLevelContext,
|
top_level: &TopLevelContext,
|
||||||
type_cache: &mut HashMap<Type, BasicTypeEnum<'ctx>>,
|
type_cache: &mut HashMap<Type, BasicTypeEnum<'ctx>>,
|
||||||
|
primitives: &PrimitiveStore,
|
||||||
ty: Type,
|
ty: Type,
|
||||||
) -> BasicTypeEnum<'ctx> {
|
) -> BasicTypeEnum<'ctx> {
|
||||||
use TypeEnum::*;
|
use TypeEnum::*;
|
||||||
@ -268,9 +269,28 @@ fn get_llvm_type<'ctx>(
|
|||||||
let ty_enum = unifier.get_ty(ty);
|
let ty_enum = unifier.get_ty(ty);
|
||||||
let result = match &*ty_enum {
|
let result = match &*ty_enum {
|
||||||
TObj { obj_id, fields, .. } => {
|
TObj { obj_id, fields, .. } => {
|
||||||
// check to avoid treating primitives as classes
|
// check to avoid treating primitives other than Option as classes
|
||||||
if obj_id.0 <= 7 {
|
if obj_id.0 <= 14 {
|
||||||
unreachable!();
|
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
|
// a struct with fields in the order of declaration
|
||||||
let top_level_defs = top_level.definitions.read();
|
let top_level_defs = top_level.definitions.read();
|
||||||
@ -289,6 +309,7 @@ fn get_llvm_type<'ctx>(
|
|||||||
unifier,
|
unifier,
|
||||||
top_level,
|
top_level,
|
||||||
type_cache,
|
type_cache,
|
||||||
|
primitives,
|
||||||
fields[&f.0].0,
|
fields[&f.0].0,
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@ -304,14 +325,14 @@ fn get_llvm_type<'ctx>(
|
|||||||
// a struct with fields in the order present in the tuple
|
// a struct with fields in the order present in the tuple
|
||||||
let fields = ty
|
let fields = ty
|
||||||
.iter()
|
.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();
|
.collect_vec();
|
||||||
ctx.struct_type(&fields, false).into()
|
ctx.struct_type(&fields, false).into()
|
||||||
}
|
}
|
||||||
TList { ty } => {
|
TList { ty } => {
|
||||||
// a struct with an integer and a pointer to an array
|
// a struct with an integer and a pointer to an array
|
||||||
let element_type =
|
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 = [
|
let fields = [
|
||||||
element_type.ptr_type(AddressSpace::Generic).into(),
|
element_type.ptr_type(AddressSpace::Generic).into(),
|
||||||
generator.get_size_type(ctx).into(),
|
generator.get_size_type(ctx).into(),
|
||||||
@ -418,7 +439,8 @@ pub fn gen_func<'ctx, G: CodeGenerator>(
|
|||||||
exception.set_body(&fields, false);
|
exception.set_body(&fields, false);
|
||||||
exception.ptr_type(AddressSpace::Generic).into()
|
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, .. } =
|
let (args, ret) = if let ConcreteTypeEnum::TFunc { args, ret, .. } =
|
||||||
task.store.get(task.signature)
|
task.store.get(task.signature)
|
||||||
@ -439,7 +461,7 @@ pub fn gen_func<'ctx, G: CodeGenerator>(
|
|||||||
let ret_type = if unifier.unioned(ret, primitives.none) {
|
let ret_type = if unifier.unioned(ret, primitives.none) {
|
||||||
None
|
None
|
||||||
} else {
|
} 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));
|
let has_sret = ret_type.map_or(false, |ty| need_sret(context, ty));
|
||||||
@ -452,6 +474,7 @@ pub fn gen_func<'ctx, G: CodeGenerator>(
|
|||||||
&mut unifier,
|
&mut unifier,
|
||||||
top_level_ctx.as_ref(),
|
top_level_ctx.as_ref(),
|
||||||
&mut type_cache,
|
&mut type_cache,
|
||||||
|
&primitives,
|
||||||
arg.ty,
|
arg.ty,
|
||||||
)
|
)
|
||||||
.into()
|
.into()
|
||||||
@ -499,6 +522,7 @@ pub fn gen_func<'ctx, G: CodeGenerator>(
|
|||||||
&mut unifier,
|
&mut unifier,
|
||||||
top_level_ctx.as_ref(),
|
top_level_ctx.as_ref(),
|
||||||
&mut type_cache,
|
&mut type_cache,
|
||||||
|
&primitives,
|
||||||
arg.ty,
|
arg.ty,
|
||||||
),
|
),
|
||||||
&arg.name.to_string(),
|
&arg.name.to_string(),
|
||||||
|
@ -105,7 +105,7 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
|
|||||||
("__param2__".into(), int64, true),
|
("__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)) =
|
let (is_some_ty, unwrap_ty, (option_ty_var, option_ty_var_id)) =
|
||||||
if let TypeEnum::TObj { fields, params, .. } =
|
if let TypeEnum::TObj { fields, params, .. } =
|
||||||
primitives.1.get_ty(primitives.0.option).as_ref()
|
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(),
|
instance_to_stmt: Default::default(),
|
||||||
resolver: None,
|
resolver: None,
|
||||||
codegen_callback: Some(Arc::new(GenCall::new(Box::new(
|
codegen_callback: Some(Arc::new(GenCall::new(Box::new(
|
||||||
|ctx, _, fun, args, generator| {
|
|ctx, obj, _, _, generator| {
|
||||||
// TODO:
|
let obj_val = obj.unwrap().1.clone().to_basic_value_enum(ctx, generator)?;
|
||||||
unimplemented!()
|
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,
|
loc: None,
|
||||||
@ -238,9 +262,13 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
|
|||||||
instance_to_stmt: Default::default(),
|
instance_to_stmt: Default::default(),
|
||||||
resolver: None,
|
resolver: None,
|
||||||
codegen_callback: Some(Arc::new(GenCall::new(Box::new(
|
codegen_callback: Some(Arc::new(GenCall::new(Box::new(
|
||||||
|ctx, _, fun, args, generator| {
|
|ctx, obj, _, _, generator| {
|
||||||
// TODO:
|
let obj_val = obj.unwrap().1.clone().to_basic_value_enum(ctx, generator)?;
|
||||||
unimplemented!()
|
if let BasicValueEnum::PointerValue(ptr) = obj_val {
|
||||||
|
Ok(Some(ctx.builder.build_load(ptr, "unwrap_some")))
|
||||||
|
} else {
|
||||||
|
unreachable!("option must be ptr")
|
||||||
|
}
|
||||||
},
|
},
|
||||||
)))),
|
)))),
|
||||||
loc: None,
|
loc: None,
|
||||||
@ -1176,8 +1204,11 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
|
|||||||
instance_to_stmt: Default::default(),
|
instance_to_stmt: Default::default(),
|
||||||
resolver: None,
|
resolver: None,
|
||||||
codegen_callback: Some(Arc::new(GenCall::new(Box::new(
|
codegen_callback: Some(Arc::new(GenCall::new(Box::new(
|
||||||
|ctx, _, fun, args, generator| {
|
|ctx, _, _fun, args, generator| {
|
||||||
unimplemented!()
|
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,
|
loc: None,
|
||||||
|
@ -123,6 +123,7 @@ impl TopLevelComposer {
|
|||||||
obj_id: DefinitionId(10),
|
obj_id: DefinitionId(10),
|
||||||
fields: vec![
|
fields: vec![
|
||||||
("is_some".into(), (is_some_type_fun_ty, true)),
|
("is_some".into(), (is_some_type_fun_ty, true)),
|
||||||
|
("is_none".into(), (is_some_type_fun_ty, true)),
|
||||||
("unwrap".into(), (unwrap_fun_ty, true)),
|
("unwrap".into(), (unwrap_fun_ty, true)),
|
||||||
]
|
]
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
Loading…
Reference in New Issue
Block a user