forked from M-Labs/nac3
nac3core: option type front end
This commit is contained in:
parent
55db05fdbb
commit
62d13e297c
@ -385,6 +385,7 @@ pub fn gen_func<'ctx, G: CodeGenerator>(
|
||||
range: unifier.get_representative(primitives.range),
|
||||
str: unifier.get_representative(primitives.str),
|
||||
exception: unifier.get_representative(primitives.exception),
|
||||
option: unifier.get_representative(primitives.option),
|
||||
};
|
||||
|
||||
let mut type_cache: HashMap<_, _> = [
|
||||
@ -417,6 +418,7 @@ pub fn gen_func<'ctx, G: CodeGenerator>(
|
||||
exception.set_body(&fields, false);
|
||||
exception.ptr_type(AddressSpace::Generic).into()
|
||||
});
|
||||
// TODO: insert option type cache
|
||||
|
||||
let (args, ret) = if let ConcreteTypeEnum::TFunc { args, ret, .. } =
|
||||
task.store.get(task.signature)
|
||||
|
@ -105,6 +105,20 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
|
||||
("__param2__".into(), int64, true),
|
||||
];
|
||||
|
||||
// for Option, is_some and is_none share the same type: () -> bool,
|
||||
// and they are methods under the same class `Option`
|
||||
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()
|
||||
{
|
||||
(
|
||||
*fields.get(&"is_some".into()).unwrap(),
|
||||
*fields.get(&"unwrap".into()).unwrap(),
|
||||
(*params.iter().next().unwrap().1, *params.iter().next().unwrap().0),
|
||||
)
|
||||
} else {
|
||||
unreachable!()
|
||||
};
|
||||
let top_level_def_list = vec![
|
||||
Arc::new(RwLock::new(TopLevelComposer::make_top_level_class_def(
|
||||
0,
|
||||
@ -180,6 +194,58 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
|
||||
None,
|
||||
None,
|
||||
))),
|
||||
Arc::new(RwLock::new({
|
||||
TopLevelDef::Class {
|
||||
name: "Option".into(),
|
||||
object_id: DefinitionId(10),
|
||||
type_vars: vec![option_ty_var],
|
||||
fields: vec![],
|
||||
methods: vec![
|
||||
("is_some".into(), is_some_ty.0, DefinitionId(11)),
|
||||
("is_none".into(), is_some_ty.0, DefinitionId(12)),
|
||||
("unwrap".into(), unwrap_ty.0, DefinitionId(13)),
|
||||
],
|
||||
ancestors: vec![TypeAnnotation::CustomClass {
|
||||
id: DefinitionId(10),
|
||||
params: Default::default(),
|
||||
}],
|
||||
constructor: None,
|
||||
resolver: None,
|
||||
loc: None,
|
||||
}
|
||||
})),
|
||||
Arc::new(RwLock::new(TopLevelDef::Function {
|
||||
name: "Option.is_some".into(),
|
||||
simple_name: "is_some".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, _, fun, args, generator| {
|
||||
// TODO:
|
||||
unimplemented!()
|
||||
},
|
||||
)))),
|
||||
loc: None,
|
||||
})),
|
||||
Arc::new(RwLock::new(TopLevelDef::Function {
|
||||
name: "Option.unwrap".into(),
|
||||
simple_name: "unwrap".into(),
|
||||
signature: unwrap_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, _, fun, args, generator| {
|
||||
// TODO:
|
||||
unimplemented!()
|
||||
},
|
||||
)))),
|
||||
loc: None,
|
||||
})),
|
||||
Arc::new(RwLock::new(TopLevelDef::Function {
|
||||
name: "int32".into(),
|
||||
simple_name: "int32".into(),
|
||||
@ -1098,6 +1164,25 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
|
||||
)))),
|
||||
loc: None,
|
||||
})),
|
||||
Arc::new(RwLock::new(TopLevelDef::Function {
|
||||
name: "Some".into(),
|
||||
simple_name: "Some".into(),
|
||||
signature: primitives.1.add_ty(TypeEnum::TFunc(FunSignature {
|
||||
args: vec![FuncArg { name: "n".into(), ty: option_ty_var, default_value: None }],
|
||||
ret: primitives.0.option,
|
||||
vars: HashMap::from([(option_ty_var_id, option_ty_var)]),
|
||||
})),
|
||||
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, _, fun, args, generator| {
|
||||
unimplemented!()
|
||||
},
|
||||
)))),
|
||||
loc: None,
|
||||
})),
|
||||
];
|
||||
|
||||
let ast_list: Vec<Option<ast::Stmt<()>>> =
|
||||
@ -1123,6 +1208,7 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
|
||||
"min",
|
||||
"max",
|
||||
"abs",
|
||||
"Some",
|
||||
],
|
||||
)
|
||||
}
|
||||
|
@ -74,6 +74,8 @@ impl TopLevelComposer {
|
||||
"self".into(),
|
||||
"Kernel".into(),
|
||||
"KernelInvariant".into(),
|
||||
"Some".into(),
|
||||
"Option".into(),
|
||||
]);
|
||||
let defined_names: HashSet<String> = Default::default();
|
||||
let method_class: HashMap<DefinitionId, DefinitionId> = Default::default();
|
||||
@ -92,7 +94,6 @@ impl TopLevelComposer {
|
||||
} else if let TopLevelDef::Class { name, constructor, object_id, type_vars, .. } = &*def
|
||||
{
|
||||
assert!(id == object_id.0);
|
||||
assert!(type_vars.is_empty());
|
||||
if let Some(constructor) = constructor {
|
||||
builtin_ty.insert(*name, *constructor);
|
||||
}
|
||||
|
@ -107,7 +107,42 @@ impl TopLevelComposer {
|
||||
fields: HashMap::new(),
|
||||
params: HashMap::new(),
|
||||
});
|
||||
let primitives = PrimitiveStore { int32, int64, float, bool, none, range, str, exception, uint32, uint64 };
|
||||
|
||||
let option_type_var = unifier.get_fresh_var(Some("option_type_var".into()), None);
|
||||
let is_some_type_fun_ty = unifier.add_ty(TypeEnum::TFunc(FunSignature {
|
||||
args: vec![],
|
||||
ret: bool,
|
||||
vars: HashMap::from([(option_type_var.1, option_type_var.0)]),
|
||||
}));
|
||||
let unwrap_fun_ty = unifier.add_ty(TypeEnum::TFunc(FunSignature {
|
||||
args: vec![],
|
||||
ret: option_type_var.0,
|
||||
vars: HashMap::from([(option_type_var.1, option_type_var.0)]),
|
||||
}));
|
||||
let option = unifier.add_ty(TypeEnum::TObj {
|
||||
obj_id: DefinitionId(10),
|
||||
fields: vec![
|
||||
("is_some".into(), (is_some_type_fun_ty, true)),
|
||||
("unwrap".into(), (unwrap_fun_ty, true)),
|
||||
]
|
||||
.into_iter()
|
||||
.collect::<HashMap<_, _>>(),
|
||||
params: HashMap::from([(option_type_var.1, option_type_var.0)]),
|
||||
});
|
||||
|
||||
let primitives = PrimitiveStore {
|
||||
int32,
|
||||
int64,
|
||||
float,
|
||||
bool,
|
||||
none,
|
||||
range,
|
||||
str,
|
||||
exception,
|
||||
uint32,
|
||||
uint64,
|
||||
option,
|
||||
};
|
||||
crate::typecheck::magic_methods::set_primitives_magic_methods(&primitives, &mut unifier);
|
||||
(primitives, unifier)
|
||||
}
|
||||
|
@ -223,6 +223,29 @@ pub fn parse_ast_to_type_annotation_kinds<T>(
|
||||
Ok(TypeAnnotation::List(def_ann.into()))
|
||||
}
|
||||
|
||||
// option
|
||||
ast::ExprKind::Subscript { value, slice, .. }
|
||||
if {
|
||||
matches!(&value.node, ast::ExprKind::Name { id, .. } if id == &"Option".into())
|
||||
} =>
|
||||
{
|
||||
let def_ann = parse_ast_to_type_annotation_kinds(
|
||||
resolver,
|
||||
top_level_defs,
|
||||
unifier,
|
||||
primitives,
|
||||
slice.as_ref(),
|
||||
locked,
|
||||
)?;
|
||||
let id =
|
||||
if let TypeEnum::TObj { obj_id, .. } = unifier.get_ty(primitives.option).as_ref() {
|
||||
*obj_id
|
||||
} else {
|
||||
unreachable!()
|
||||
};
|
||||
Ok(TypeAnnotation::CustomClass { id, params: vec![def_ann] })
|
||||
}
|
||||
|
||||
// tuple
|
||||
ast::ExprKind::Subscript { value, slice, .. }
|
||||
if {
|
||||
|
@ -40,6 +40,7 @@ pub struct PrimitiveStore {
|
||||
pub range: Type,
|
||||
pub str: Type,
|
||||
pub exception: Type,
|
||||
pub option: Type,
|
||||
}
|
||||
|
||||
pub struct FunctionData {
|
||||
@ -932,6 +933,17 @@ impl<'a> Inferencer<'a> {
|
||||
Ok(self.unifier.add_ty(TypeEnum::TTuple { ty: ty? }))
|
||||
}
|
||||
ast::Constant::Str(_) => Ok(self.primitives.str),
|
||||
ast::Constant::None => {
|
||||
let option_ty = self.primitives.option;
|
||||
let new_mapping = if let TypeEnum::TObj { params, .. } = &*self.unifier.get_ty_immutable(option_ty) {
|
||||
let (id, _) = params.iter().next().unwrap();
|
||||
// None can be Option[Any]
|
||||
vec![(*id, self.unifier.get_fresh_var(None, None).0)].into_iter().collect()
|
||||
} else {
|
||||
unreachable!("option must be tobj")
|
||||
};
|
||||
Ok(self.unifier.subst(option_ty, &new_mapping).unwrap())
|
||||
}
|
||||
_ => report_error("not supported", *loc),
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user