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),
|
range: unifier.get_representative(primitives.range),
|
||||||
str: unifier.get_representative(primitives.str),
|
str: unifier.get_representative(primitives.str),
|
||||||
exception: unifier.get_representative(primitives.exception),
|
exception: unifier.get_representative(primitives.exception),
|
||||||
|
option: unifier.get_representative(primitives.option),
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut type_cache: HashMap<_, _> = [
|
let mut type_cache: HashMap<_, _> = [
|
||||||
|
@ -417,6 +418,7 @@ 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
|
||||||
|
|
||||||
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)
|
||||||
|
|
|
@ -105,6 +105,20 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
|
||||||
("__param2__".into(), int64, true),
|
("__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![
|
let top_level_def_list = vec![
|
||||||
Arc::new(RwLock::new(TopLevelComposer::make_top_level_class_def(
|
Arc::new(RwLock::new(TopLevelComposer::make_top_level_class_def(
|
||||||
0,
|
0,
|
||||||
|
@ -180,6 +194,58 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
|
||||||
None,
|
None,
|
||||||
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 {
|
Arc::new(RwLock::new(TopLevelDef::Function {
|
||||||
name: "int32".into(),
|
name: "int32".into(),
|
||||||
simple_name: "int32".into(),
|
simple_name: "int32".into(),
|
||||||
|
@ -1098,6 +1164,25 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
|
||||||
)))),
|
)))),
|
||||||
loc: None,
|
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<()>>> =
|
let ast_list: Vec<Option<ast::Stmt<()>>> =
|
||||||
|
@ -1123,6 +1208,7 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
|
||||||
"min",
|
"min",
|
||||||
"max",
|
"max",
|
||||||
"abs",
|
"abs",
|
||||||
|
"Some",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,6 +74,8 @@ impl TopLevelComposer {
|
||||||
"self".into(),
|
"self".into(),
|
||||||
"Kernel".into(),
|
"Kernel".into(),
|
||||||
"KernelInvariant".into(),
|
"KernelInvariant".into(),
|
||||||
|
"Some".into(),
|
||||||
|
"Option".into(),
|
||||||
]);
|
]);
|
||||||
let defined_names: HashSet<String> = Default::default();
|
let defined_names: HashSet<String> = Default::default();
|
||||||
let method_class: HashMap<DefinitionId, DefinitionId> = 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
|
} else if let TopLevelDef::Class { name, constructor, object_id, type_vars, .. } = &*def
|
||||||
{
|
{
|
||||||
assert!(id == object_id.0);
|
assert!(id == object_id.0);
|
||||||
assert!(type_vars.is_empty());
|
|
||||||
if let Some(constructor) = constructor {
|
if let Some(constructor) = constructor {
|
||||||
builtin_ty.insert(*name, *constructor);
|
builtin_ty.insert(*name, *constructor);
|
||||||
}
|
}
|
||||||
|
|
|
@ -107,7 +107,42 @@ impl TopLevelComposer {
|
||||||
fields: HashMap::new(),
|
fields: HashMap::new(),
|
||||||
params: 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);
|
crate::typecheck::magic_methods::set_primitives_magic_methods(&primitives, &mut unifier);
|
||||||
(primitives, unifier)
|
(primitives, unifier)
|
||||||
}
|
}
|
||||||
|
|
|
@ -223,6 +223,29 @@ pub fn parse_ast_to_type_annotation_kinds<T>(
|
||||||
Ok(TypeAnnotation::List(def_ann.into()))
|
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
|
// tuple
|
||||||
ast::ExprKind::Subscript { value, slice, .. }
|
ast::ExprKind::Subscript { value, slice, .. }
|
||||||
if {
|
if {
|
||||||
|
|
|
@ -40,6 +40,7 @@ pub struct PrimitiveStore {
|
||||||
pub range: Type,
|
pub range: Type,
|
||||||
pub str: Type,
|
pub str: Type,
|
||||||
pub exception: Type,
|
pub exception: Type,
|
||||||
|
pub option: Type,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct FunctionData {
|
pub struct FunctionData {
|
||||||
|
@ -932,6 +933,17 @@ impl<'a> Inferencer<'a> {
|
||||||
Ok(self.unifier.add_ty(TypeEnum::TTuple { ty: ty? }))
|
Ok(self.unifier.add_ty(TypeEnum::TTuple { ty: ty? }))
|
||||||
}
|
}
|
||||||
ast::Constant::Str(_) => Ok(self.primitives.str),
|
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),
|
_ => report_error("not supported", *loc),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue