Compare commits

..

2 Commits

Author SHA1 Message Date
2317516cf6 core: Use tvars from ndarray for class definition 2024-03-04 23:58:02 +08:00
77de24ef74 core: Use BTreeMap for type variable mapping
There have been multiple instances where I had the need to iterate over
type variables, only to discover that the traversal order is arbitrary.

This commit fixes that by adding SortedMapping, which utilizes BTreeMap
internally to guarantee a traversal order. All instances of VarMap are
now refactored to use this to ensure that type variables are iterated in
 the order of its variable ID, which should be monotonically incremented
 by the unifier.
2024-03-04 23:56:04 +08:00
24 changed files with 158 additions and 139 deletions

View File

@ -7,7 +7,7 @@ use nac3core::{
},
symbol_resolver::ValueEnum,
toplevel::{DefinitionId, GenCall, helper::PRIMITIVE_DEF_IDS},
typecheck::typedef::{FunSignature, FuncArg, Type, TypeEnum}
typecheck::typedef::{FunSignature, FuncArg, Type, TypeEnum, VarMap}
};
use nac3parser::ast::{Expr, ExprKind, Located, Stmt, StmtKind, StrRef};
@ -667,7 +667,7 @@ pub fn attributes_writeback(
default_value: None
}).collect(),
ret: ctx.primitives.none,
vars: HashMap::default()
vars: VarMap::default()
};
let args: Vec<_> = values.into_iter().map(|(_, val)| (None, ValueEnum::Dynamic(val))).collect();
if let Err(e) = rpc_codegen_callback_fn(ctx, None, (&fun, PRIMITIVE_DEF_IDS.int32), args, generator) {

View File

@ -16,7 +16,7 @@ use inkwell::{
use itertools::Itertools;
use nac3core::codegen::{CodeGenLLVMOptions, CodeGenTargetMachineOptions, gen_func_impl};
use nac3core::toplevel::builtins::get_exn_constructor;
use nac3core::typecheck::typedef::{TypeEnum, Unifier};
use nac3core::typecheck::typedef::{TypeEnum, Unifier, VarMap};
use nac3parser::{
ast::{ExprKind, Stmt, StmtKind, StrRef},
parser::parse_program,
@ -476,7 +476,7 @@ impl Nac3 {
.unwrap();
let fun_signature =
FunSignature { args: vec![], ret: self.primitive.none, vars: HashMap::new() };
FunSignature { args: vec![], ret: self.primitive.none, vars: VarMap::new() };
let mut store = ConcreteTypeStore::new();
let mut cache = HashMap::new();
let signature =
@ -816,7 +816,7 @@ impl Nac3 {
let builtins = vec![
(
"now_mu".into(),
FunSignature { args: vec![], ret: primitive.int64, vars: HashMap::new() },
FunSignature { args: vec![], ret: primitive.int64, vars: VarMap::new() },
Arc::new(GenCall::new(Box::new(move |ctx, _, _, _, _| {
Ok(Some(time_fns.emit_now_mu(ctx)))
}))),
@ -830,7 +830,7 @@ impl Nac3 {
default_value: None,
}],
ret: primitive.none,
vars: HashMap::new(),
vars: VarMap::new(),
},
Arc::new(GenCall::new(Box::new(move |ctx, _, fun, args, generator| {
let arg_ty = fun.0.args[0].ty;
@ -848,7 +848,7 @@ impl Nac3 {
default_value: None,
}],
ret: primitive.none,
vars: HashMap::new(),
vars: VarMap::new(),
},
Arc::new(GenCall::new(Box::new(move |ctx, _, fun, args, generator| {
let arg_ty = fun.0.args[0].ty;

View File

@ -10,7 +10,7 @@ use nac3core::{
},
typecheck::{
type_inferencer::PrimitiveStore,
typedef::{Type, TypeEnum, Unifier},
typedef::{Type, TypeEnum, Unifier, VarMap},
},
};
use nac3parser::ast::{self, StrRef};
@ -519,7 +519,7 @@ impl InnerResolver {
.iter()
.zip(args.iter())
.map(|((id, _), ty)| (*id, *ty))
.collect::<HashMap<_, _>>()
.collect::<VarMap>()
};
Ok(Ok((unifier.subst(origin_ty, &subst).unwrap_or(origin_ty), true)))
}
@ -722,7 +722,7 @@ impl InnerResolver {
assert_eq!(*id, *id_var);
(*id, unifier.get_fresh_var_with_range(range, *name, *loc).0)
})
.collect::<HashMap<_, _>>();
.collect::<VarMap>();
return Ok(Ok(unifier.subst(primitives.option, &var_map).unwrap()))
}
@ -734,7 +734,7 @@ impl InnerResolver {
)))
}
};
let new_var_map: HashMap<_, _> = params.iter().map(|(id, _)| (*id, ty)).collect();
let new_var_map: VarMap = params.iter().map(|(id, _)| (*id, ty)).collect();
let res = unifier.subst(extracted_ty, &new_var_map).unwrap_or(extracted_ty);
Ok(Ok(res))
}
@ -751,7 +751,7 @@ impl InnerResolver {
assert_eq!(*id, *id_var);
(*id, unifier.get_fresh_var_with_range(range, *name, *loc).0)
})
.collect::<HashMap<_, _>>();
.collect::<VarMap>();
let mut instantiate_obj = || {
// loop through non-function fields of the class to get the instantiated value
for field in fields {

View File

@ -3,7 +3,7 @@ use crate::{
toplevel::DefinitionId,
typecheck::{
type_inferencer::PrimitiveStore,
typedef::{FunSignature, FuncArg, Type, TypeEnum, Unifier},
typedef::{FunSignature, FuncArg, Type, TypeEnum, Unifier, VarMap},
},
};
@ -274,7 +274,7 @@ impl ConcreteTypeStore {
params: params
.iter()
.map(|(id, cty)| (*id, self.to_unifier_type(unifier, primitives, *cty, cache)))
.collect::<HashMap<_, _>>(),
.collect::<VarMap>(),
},
ConcreteTypeEnum::TFunc { args, ret, vars } => TypeEnum::TFunc(FunSignature {
args: args
@ -289,7 +289,7 @@ impl ConcreteTypeStore {
vars: vars
.iter()
.map(|(id, cty)| (*id, self.to_unifier_type(unifier, primitives, *cty, cache)))
.collect::<HashMap<_, _>>(),
.collect::<VarMap>(),
}),
ConcreteTypeEnum::TLiteral { values, .. } => TypeEnum::TLiteral {
values: values.clone(),

View File

@ -20,7 +20,7 @@ use crate::{
TopLevelDef,
},
typecheck::{
typedef::{FunSignature, FuncArg, Type, TypeEnum, Unifier},
typedef::{FunSignature, FuncArg, Type, TypeEnum, Unifier, VarMap},
magic_methods::{binop_name, binop_assign_name},
},
};
@ -41,7 +41,7 @@ use super::{CodeGenerator, llvm_intrinsics::call_memcpy_generic, need_sret};
pub fn get_subst_key(
unifier: &mut Unifier,
obj: Option<Type>,
fun_vars: &HashMap<u32, Type>,
fun_vars: &VarMap,
filter: Option<&Vec<u32>>,
) -> String {
let mut vars = obj

View File

@ -25,6 +25,7 @@ use nac3parser::{
use parking_lot::RwLock;
use std::collections::{HashMap, HashSet};
use std::sync::Arc;
use crate::typecheck::typedef::VarMap;
struct Resolver {
id_to_type: HashMap<StrRef, Type>,
@ -111,7 +112,7 @@ fn test_primitives() {
FuncArg { name: "b".into(), ty: primitives.int32, default_value: None },
],
ret: primitives.int32,
vars: HashMap::new(),
vars: VarMap::new(),
};
let mut store = ConcreteTypeStore::new();
@ -258,7 +259,7 @@ fn test_simple_call() {
let signature = FunSignature {
args: vec![FuncArg { name: "a".into(), ty: primitives.int32, default_value: None }],
ret: primitives.int32,
vars: HashMap::new(),
vars: VarMap::new(),
};
let fun_ty = unifier.add_ty(TypeEnum::TFunc(signature.clone()));
let mut store = ConcreteTypeStore::new();

View File

@ -8,7 +8,7 @@ use crate::{
toplevel::{DefinitionId, TopLevelDef, type_annotation::TypeAnnotation},
typecheck::{
type_inferencer::PrimitiveStore,
typedef::{Type, TypeEnum, Unifier},
typedef::{Type, TypeEnum, Unifier, VarMap},
},
};
use inkwell::values::{BasicValueEnum, FloatValue, IntValue, PointerValue, StructValue};
@ -426,7 +426,7 @@ pub fn parse_type_annotation<T>(
Ok(unifier.add_ty(TypeEnum::TObj {
obj_id,
fields,
params: HashMap::default(),
params: VarMap::default(),
}))
} else {
Err(HashSet::from([
@ -515,7 +515,7 @@ pub fn parse_type_annotation<T>(
),
]))
}
let mut subst = HashMap::new();
let mut subst = VarMap::new();
for (var, ty) in izip!(type_vars.iter(), types.iter()) {
let id = if let TypeEnum::TVar { id, .. } = &*unifier.get_ty(*var) {
*id

View File

@ -10,6 +10,7 @@ use crate::{
symbol_resolver::SymbolValue,
toplevel::helper::PRIMITIVE_DEF_IDS,
toplevel::numpy::*,
typecheck::typedef::VarMap,
};
use inkwell::{
attributes::{Attribute, AttributeLoc},
@ -56,12 +57,12 @@ pub fn get_exn_constructor(
let exn_type = unifier.add_ty(TypeEnum::TObj {
obj_id: DefinitionId(class_id),
fields: exception_fields.iter().map(|(a, b, c)| (*a, (*b, *c))).collect(),
params: HashMap::default(),
params: VarMap::default(),
});
let signature = unifier.add_ty(TypeEnum::TFunc(FunSignature {
args: exn_cons_args,
ret: exn_type,
vars: HashMap::default(),
vars: VarMap::default(),
}));
let fun_def = TopLevelDef::Function {
name: format!("{name}.__init__"),
@ -100,7 +101,7 @@ pub fn get_exn_constructor(
/// * `codegen_callback`: A lambda generating LLVM IR for the implementation of this function.
fn create_fn_by_codegen(
primitives: &mut (PrimitiveStore, Unifier),
var_map: &HashMap<u32, Type>,
var_map: &VarMap,
name: &'static str,
ret_ty: Type,
param_ty: &[(Type, &'static str)],
@ -136,7 +137,7 @@ fn create_fn_by_codegen(
/// * `intrinsic_fn`: The fully-qualified name of the LLVM intrinsic function.
fn create_fn_by_intrinsic(
primitives: &mut (PrimitiveStore, Unifier),
var_map: &HashMap<u32, Type>,
var_map: &VarMap,
name: &'static str,
ret_ty: Type,
params: &[(Type, &'static str)],
@ -200,7 +201,7 @@ fn create_fn_by_intrinsic(
/// already implied by the C ABI.
fn create_fn_by_extern(
primitives: &mut (PrimitiveStore, Unifier),
var_map: &HashMap<u32, Type>,
var_map: &VarMap,
name: &'static str,
ret_ty: Type,
params: &[(Type, &'static str)],
@ -295,7 +296,7 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
Some("N".into()),
None,
);
let var_map: HashMap<_, _> = vec![(num_ty.1, num_ty.0)].into_iter().collect();
let var_map: VarMap = vec![(num_ty.1, num_ty.0)].into_iter().collect();
let exception_fields = vec![
("__name__".into(), int32, true),
("__file__".into(), string, true),
@ -322,6 +323,17 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
} else {
unreachable!()
};
let (
(ndarray_dtype_ty, _),
(ndarray_ndims_ty, _),
) = if let TypeEnum::TObj { params, .. } = &*primitives.1.get_ty(primitives.0.ndarray) {
(
params.iter().next().map(|(var_id, ty)| (*ty, *var_id)).unwrap(),
params.iter().nth(1).map(|(var_id, ty)| (*ty, *var_id)).unwrap(),
)
} else {
unreachable!()
};
let top_level_def_list = vec![
Arc::new(RwLock::new(TopLevelComposer::make_top_level_class_def(
PRIMITIVE_DEF_IDS.int32,
@ -490,22 +502,17 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
)))),
loc: None,
})),
{
let tvar = primitives.1.get_fresh_var(Some("T".into()), None);
let ndims = primitives.1.get_fresh_const_generic_var(primitives.0.uint64, Some("N".into()), None);
Arc::new(RwLock::new(TopLevelDef::Class {
name: "ndarray".into(),
object_id: PRIMITIVE_DEF_IDS.ndarray,
type_vars: vec![tvar.0, ndims.0],
fields: Vec::default(),
methods: Vec::default(),
ancestors: Vec::default(),
constructor: None,
resolver: None,
loc: None,
}))
},
Arc::new(RwLock::new(TopLevelDef::Class {
name: "ndarray".into(),
object_id: PRIMITIVE_DEF_IDS.ndarray,
type_vars: vec![ndarray_dtype_ty, ndarray_ndims_ty],
fields: Vec::default(),
methods: Vec::default(),
ancestors: Vec::default(),
constructor: None,
resolver: None,
loc: None,
})),
Arc::new(RwLock::new(TopLevelDef::Function {
name: "int32".into(),
simple_name: "int32".into(),
@ -1057,7 +1064,7 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
},
],
ret: range,
vars: HashMap::default(),
vars: VarMap::default(),
})),
var_id: Vec::default(),
instance_to_symbol: HashMap::default(),
@ -1149,7 +1156,7 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
signature: primitives.1.add_ty(TypeEnum::TFunc(FunSignature {
args: vec![FuncArg { name: "s".into(), ty: string, default_value: None }],
ret: string,
vars: HashMap::default(),
vars: VarMap::default(),
})),
var_id: Vec::default(),
instance_to_symbol: HashMap::default(),
@ -1971,7 +1978,7 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
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)]),
vars: VarMap::from([(option_ty_var_id, option_ty_var)]),
})),
var_id: vec![option_ty_var_id],
instance_to_symbol: HashMap::default(),

View File

@ -4,7 +4,10 @@ use std::rc::Rc;
use crate::{
codegen::{expr::get_subst_key, stmt::exn_constructor},
symbol_resolver::SymbolValue,
typecheck::type_inferencer::{FunctionData, Inferencer},
typecheck::{
type_inferencer::{FunctionData, Inferencer},
typedef::VarMap,
},
};
use super::*;
@ -844,7 +847,7 @@ impl TopLevelComposer {
let resolver = resolver.unwrap();
let resolver = &**resolver;
let mut function_var_map: HashMap<u32, Type> = HashMap::new();
let mut function_var_map = VarMap::new();
let arg_types = {
// make sure no duplicate parameter
let mut defined_parameter_name: HashSet<_> = HashSet::new();
@ -1082,7 +1085,7 @@ impl TopLevelComposer {
let (method_dummy_ty, method_id) =
Self::get_class_method_def_info(class_methods_def, *name)?;
let mut method_var_map: HashMap<u32, Type> = HashMap::new();
let mut method_var_map = VarMap::new();
let arg_types: Vec<FuncArg> = {
// check method parameters cannot have same name
@ -1574,7 +1577,7 @@ impl TopLevelComposer {
},
],
ret: self_type,
vars: HashMap::default(),
vars: VarMap::default(),
}));
let cons_fun = TopLevelDef::Function {
name: format!("{}.{}", class_name, "__init__"),
@ -1598,7 +1601,7 @@ impl TopLevelComposer {
// get the class constructor type correct
let (contor_args, contor_type_vars) = {
let mut constructor_args: Vec<FuncArg> = Vec::new();
let mut type_vars: HashMap<u32, Type> = HashMap::new();
let mut type_vars = VarMap::new();
for (name, func_sig, id) in methods {
if *name == init_str_id {
init_id = Some(*id);
@ -1749,13 +1752,13 @@ impl TopLevelComposer {
})
.multi_cartesian_product()
.collect_vec();
let mut result: Vec<HashMap<u32, Type>> = Vec::default();
let mut result: Vec<VarMap> = Vec::default();
for comb in var_combs {
result.push(vars.keys().copied().zip(comb).collect());
}
// NOTE: if is empty, means no type var, append a empty subst, ok to do this?
if result.is_empty() {
result.push(HashMap::new());
result.push(VarMap::new());
}
(result, no_ranges)
};
@ -1795,7 +1798,7 @@ impl TopLevelComposer {
None
}
})
.collect::<HashMap<_, _>>()
.collect::<VarMap>()
};
unifier.subst(self_type, &subst_for_self).unwrap_or(self_type)
})

View File

@ -1,7 +1,7 @@
use std::convert::TryInto;
use crate::symbol_resolver::SymbolValue;
use crate::typecheck::typedef::Mapping;
use crate::typecheck::typedef::{Mapping, VarMap};
use nac3parser::ast::{Constant, Location};
use super::*;
@ -112,37 +112,37 @@ impl TopLevelComposer {
let int32 = unifier.add_ty(TypeEnum::TObj {
obj_id: PRIMITIVE_DEF_IDS.int32,
fields: HashMap::new(),
params: HashMap::new(),
params: VarMap::new(),
});
let int64 = unifier.add_ty(TypeEnum::TObj {
obj_id: PRIMITIVE_DEF_IDS.int64,
fields: HashMap::new(),
params: HashMap::new(),
params: VarMap::new(),
});
let float = unifier.add_ty(TypeEnum::TObj {
obj_id: PRIMITIVE_DEF_IDS.float,
fields: HashMap::new(),
params: HashMap::new(),
params: VarMap::new(),
});
let bool = unifier.add_ty(TypeEnum::TObj {
obj_id: PRIMITIVE_DEF_IDS.bool,
fields: HashMap::new(),
params: HashMap::new(),
params: VarMap::new(),
});
let none = unifier.add_ty(TypeEnum::TObj {
obj_id: PRIMITIVE_DEF_IDS.none,
fields: HashMap::new(),
params: HashMap::new(),
params: VarMap::new(),
});
let range = unifier.add_ty(TypeEnum::TObj {
obj_id: PRIMITIVE_DEF_IDS.range,
fields: HashMap::new(),
params: HashMap::new(),
params: VarMap::new(),
});
let str = unifier.add_ty(TypeEnum::TObj {
obj_id: PRIMITIVE_DEF_IDS.str,
fields: HashMap::new(),
params: HashMap::new(),
params: VarMap::new(),
});
let exception = unifier.add_ty(TypeEnum::TObj {
obj_id: PRIMITIVE_DEF_IDS.exception,
@ -159,29 +159,29 @@ impl TopLevelComposer {
]
.into_iter()
.collect::<HashMap<_, _>>(),
params: HashMap::new(),
params: VarMap::new(),
});
let uint32 = unifier.add_ty(TypeEnum::TObj {
obj_id: PRIMITIVE_DEF_IDS.uint32,
fields: HashMap::new(),
params: HashMap::new(),
params: VarMap::new(),
});
let uint64 = unifier.add_ty(TypeEnum::TObj {
obj_id: PRIMITIVE_DEF_IDS.uint64,
fields: HashMap::new(),
params: HashMap::new(),
params: VarMap::new(),
});
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)]),
vars: VarMap::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)]),
vars: VarMap::from([(option_type_var.1, option_type_var.0)]),
}));
let option = unifier.add_ty(TypeEnum::TObj {
obj_id: PRIMITIVE_DEF_IDS.option,
@ -192,7 +192,7 @@ impl TopLevelComposer {
]
.into_iter()
.collect::<HashMap<_, _>>(),
params: HashMap::from([(option_type_var.1, option_type_var.0)]),
params: VarMap::from([(option_type_var.1, option_type_var.0)]),
});
let size_t_ty = match size_t {
@ -206,10 +206,10 @@ impl TopLevelComposer {
let ndarray = unifier.add_ty(TypeEnum::TObj {
obj_id: PRIMITIVE_DEF_IDS.ndarray,
fields: Mapping::new(),
params: Mapping::from([
params: VarMap::from([
(ndarray_dtype_tvar.1, ndarray_dtype_tvar.0),
(ndarray_ndims_tvar.1, ndarray_ndims_tvar.0),
])
]),
});
let primitives = PrimitiveStore {

View File

@ -8,7 +8,7 @@ use std::{
use super::codegen::CodeGenContext;
use super::typecheck::type_inferencer::PrimitiveStore;
use super::typecheck::typedef::{FunSignature, FuncArg, SharedUnifier, Type, TypeEnum, Unifier};
use super::typecheck::typedef::{FunSignature, FuncArg, SharedUnifier, Type, TypeEnum, Unifier, VarMap};
use crate::{
codegen::CodeGenerator,
symbol_resolver::{SymbolResolver, ValueEnum},
@ -76,7 +76,7 @@ impl Debug for GenCall {
pub struct FunInstance {
pub body: Arc<Vec<Stmt<Option<Type>>>>,
pub calls: Arc<HashMap<CodeLocation, CallId>>,
pub subst: HashMap<u32, Type>,
pub subst: VarMap,
pub unifier_id: usize,
}

View File

@ -19,7 +19,7 @@ use crate::{
toplevel::{DefinitionId, helper::PRIMITIVE_DEF_IDS},
typecheck::{
type_inferencer::PrimitiveStore,
typedef::{FunSignature, Mapping, Type, TypeEnum, Unifier},
typedef::{FunSignature, Type, TypeEnum, Unifier, VarMap},
},
};
@ -48,7 +48,7 @@ pub fn make_ndarray_ty(
.collect_vec();
debug_assert_eq!(tvar_ids.len(), 2);
let mut tvar_subst = Mapping::new();
let mut tvar_subst = VarMap::new();
if let Some(dtype) = dtype {
tvar_subst.insert(tvar_ids[0], dtype);
}

View File

@ -5,7 +5,7 @@ expression: res_vec
[
"Class {\nname: \"Generic_A\",\nancestors: [\"Generic_A[V]\", \"B\"],\nfields: [\"aa\", \"a\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"foo\", \"fn[[b:T], none]\"), (\"fun\", \"fn[[a:int32], V]\")],\ntype_vars: [\"V\"]\n}\n",
"Function {\nname: \"Generic_A.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
"Function {\nname: \"Generic_A.fun\",\nsig: \"fn[[a:int32], V]\",\nvar_id: [28]\n}\n",
"Function {\nname: \"Generic_A.fun\",\nsig: \"fn[[a:int32], V]\",\nvar_id: [26]\n}\n",
"Class {\nname: \"B\",\nancestors: [\"B\"],\nfields: [\"aa\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"foo\", \"fn[[b:T], none]\")],\ntype_vars: []\n}\n",
"Function {\nname: \"B.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
"Function {\nname: \"B.foo\",\nsig: \"fn[[b:T], none]\",\nvar_id: []\n}\n",

View File

@ -7,7 +7,7 @@ expression: res_vec
"Function {\nname: \"A.__init__\",\nsig: \"fn[[t:T], none]\",\nvar_id: []\n}\n",
"Function {\nname: \"A.fun\",\nsig: \"fn[[a:int32, b:T], list[virtual[B[bool]]]]\",\nvar_id: []\n}\n",
"Function {\nname: \"A.foo\",\nsig: \"fn[[c:C], none]\",\nvar_id: []\n}\n",
"Class {\nname: \"B\",\nancestors: [\"B[typevar17]\", \"A[float]\"],\nfields: [\"a\", \"b\", \"c\", \"d\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"fun\", \"fn[[a:int32, b:T], list[virtual[B[bool]]]]\"), (\"foo\", \"fn[[c:C], none]\")],\ntype_vars: [\"typevar17\"]\n}\n",
"Class {\nname: \"B\",\nancestors: [\"B[typevar15]\", \"A[float]\"],\nfields: [\"a\", \"b\", \"c\", \"d\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"fun\", \"fn[[a:int32, b:T], list[virtual[B[bool]]]]\"), (\"foo\", \"fn[[c:C], none]\")],\ntype_vars: [\"typevar15\"]\n}\n",
"Function {\nname: \"B.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
"Function {\nname: \"B.fun\",\nsig: \"fn[[a:int32, b:T], list[virtual[B[bool]]]]\",\nvar_id: []\n}\n",
"Class {\nname: \"C\",\nancestors: [\"C\", \"B[bool]\", \"A[float]\"],\nfields: [\"a\", \"b\", \"c\", \"d\", \"e\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"fun\", \"fn[[a:int32, b:T], list[virtual[B[bool]]]]\"), (\"foo\", \"fn[[c:C], none]\")],\ntype_vars: []\n}\n",

View File

@ -5,8 +5,8 @@ expression: res_vec
[
"Function {\nname: \"foo\",\nsig: \"fn[[a:list[int32], b:tuple[T, float]], A[B, bool]]\",\nvar_id: []\n}\n",
"Class {\nname: \"A\",\nancestors: [\"A[T, V]\"],\nfields: [\"a\", \"b\"],\nmethods: [(\"__init__\", \"fn[[v:V], none]\"), (\"fun\", \"fn[[a:T], V]\")],\ntype_vars: [\"T\", \"V\"]\n}\n",
"Function {\nname: \"A.__init__\",\nsig: \"fn[[v:V], none]\",\nvar_id: [30]\n}\n",
"Function {\nname: \"A.fun\",\nsig: \"fn[[a:T], V]\",\nvar_id: [35]\n}\n",
"Function {\nname: \"A.__init__\",\nsig: \"fn[[v:V], none]\",\nvar_id: [28]\n}\n",
"Function {\nname: \"A.fun\",\nsig: \"fn[[a:T], V]\",\nvar_id: [33]\n}\n",
"Function {\nname: \"gfun\",\nsig: \"fn[[a:A[int32, list[float]]], none]\",\nvar_id: []\n}\n",
"Class {\nname: \"B\",\nancestors: [\"B\"],\nfields: [],\nmethods: [(\"__init__\", \"fn[[], none]\")],\ntype_vars: []\n}\n",
"Function {\nname: \"B.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",

View File

@ -3,7 +3,7 @@ source: nac3core/src/toplevel/test.rs
expression: res_vec
---
[
"Class {\nname: \"A\",\nancestors: [\"A[typevar16, typevar17]\"],\nfields: [\"a\", \"b\"],\nmethods: [(\"__init__\", \"fn[[a:A[bool, float], b:B], none]\"), (\"fun\", \"fn[[a:A[bool, float]], A[bool, int32]]\")],\ntype_vars: [\"typevar16\", \"typevar17\"]\n}\n",
"Class {\nname: \"A\",\nancestors: [\"A[typevar14, typevar15]\"],\nfields: [\"a\", \"b\"],\nmethods: [(\"__init__\", \"fn[[a:A[bool, float], b:B], none]\"), (\"fun\", \"fn[[a:A[bool, float]], A[bool, int32]]\")],\ntype_vars: [\"typevar14\", \"typevar15\"]\n}\n",
"Function {\nname: \"A.__init__\",\nsig: \"fn[[a:A[bool, float], b:B], none]\",\nvar_id: []\n}\n",
"Function {\nname: \"A.fun\",\nsig: \"fn[[a:A[bool, float]], A[bool, int32]]\",\nvar_id: []\n}\n",
"Class {\nname: \"B\",\nancestors: [\"B\", \"A[int64, bool]\"],\nfields: [\"a\", \"b\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"fun\", \"fn[[a:A[bool, float]], A[bool, int32]]\"), (\"foo\", \"fn[[b:B], B]\"), (\"bar\", \"fn[[a:A[int32, list[B]]], tuple[A[bool, virtual[A[B, int32]]], B]]\")],\ntype_vars: []\n}\n",

View File

@ -6,12 +6,12 @@ expression: res_vec
"Class {\nname: \"A\",\nancestors: [\"A\"],\nfields: [\"a\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"fun\", \"fn[[b:B], none]\"), (\"foo\", \"fn[[a:T, b:V], none]\")],\ntype_vars: []\n}\n",
"Function {\nname: \"A.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
"Function {\nname: \"A.fun\",\nsig: \"fn[[b:B], none]\",\nvar_id: []\n}\n",
"Function {\nname: \"A.foo\",\nsig: \"fn[[a:T, b:V], none]\",\nvar_id: [36]\n}\n",
"Function {\nname: \"A.foo\",\nsig: \"fn[[a:T, b:V], none]\",\nvar_id: [34]\n}\n",
"Class {\nname: \"B\",\nancestors: [\"B\", \"C\", \"A\"],\nfields: [\"a\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"fun\", \"fn[[b:B], none]\"), (\"foo\", \"fn[[a:T, b:V], none]\")],\ntype_vars: []\n}\n",
"Function {\nname: \"B.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
"Class {\nname: \"C\",\nancestors: [\"C\", \"A\"],\nfields: [\"a\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"fun\", \"fn[[b:B], none]\"), (\"foo\", \"fn[[a:T, b:V], none]\")],\ntype_vars: []\n}\n",
"Function {\nname: \"C.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
"Function {\nname: \"C.fun\",\nsig: \"fn[[b:B], none]\",\nvar_id: []\n}\n",
"Function {\nname: \"foo\",\nsig: \"fn[[a:A], none]\",\nvar_id: []\n}\n",
"Function {\nname: \"ff\",\nsig: \"fn[[a:T], V]\",\nvar_id: [44]\n}\n",
"Function {\nname: \"ff\",\nsig: \"fn[[a:T], V]\",\nvar_id: [42]\n}\n",
]

View File

@ -415,7 +415,7 @@ pub fn get_type_from_type_annotation_kinds(
let subst = {
// check for compatible range
// TODO: if allow type var to be applied(now this disallowed in the parse_to_type_annotation), need more check
let mut result: HashMap<u32, Type> = HashMap::new();
let mut result = VarMap::new();
for (tvar, p) in type_vars.iter().zip(param_ty) {
match unifier.get_ty(*tvar).as_ref() {
TypeEnum::TVar { id, range, fields: None, name, loc, is_const_generic: false } => {

View File

@ -1,6 +1,6 @@
use crate::typecheck::{
type_inferencer::*,
typedef::{FunSignature, FuncArg, Type, TypeEnum, Unifier},
typedef::{FunSignature, FuncArg, Type, TypeEnum, Unifier, VarMap},
};
use nac3parser::ast::StrRef;
use nac3parser::ast::{Cmpop, Operator, Unaryop};
@ -102,9 +102,9 @@ pub fn impl_binop(
};
let function_vars = if let Some(var_id) = other_var_id {
vec![(var_id, other_ty)].into_iter().collect::<HashMap<_, _>>()
vec![(var_id, other_ty)].into_iter().collect::<VarMap>()
} else {
HashMap::new()
VarMap::new()
};
for op in ops {
@ -149,7 +149,7 @@ pub fn impl_unaryop(unifier: &mut Unifier, ty: Type, ret_ty: Type, ops: &[Unaryo
(
unifier.add_ty(TypeEnum::TFunc(FunSignature {
ret: ret_ty,
vars: HashMap::new(),
vars: VarMap::new(),
args: vec![],
})),
false,
@ -173,7 +173,7 @@ pub fn impl_cmpop(
(
unifier.add_ty(TypeEnum::TFunc(FunSignature {
ret: store.bool,
vars: HashMap::new(),
vars: VarMap::new(),
args: vec![FuncArg {
ty: other_ty,
default_value: None,

View File

@ -3,7 +3,7 @@ use std::convert::{From, TryInto};
use std::iter::once;
use std::{cell::RefCell, sync::Arc};
use super::typedef::{Call, FunSignature, FuncArg, RecordField, Type, TypeEnum, Unifier};
use super::typedef::{Call, FunSignature, FuncArg, RecordField, Type, TypeEnum, Unifier, VarMap};
use super::{magic_methods::*, typedef::CallId};
use crate::{
symbol_resolver::{SymbolResolver, SymbolValue},
@ -425,13 +425,13 @@ impl<'a> Fold<()> for Inferencer<'a> {
|| self.unifier.get_dummy_var().0,
|var| var.custom.unwrap(),
),
vars: HashMap::default(),
vars: VarMap::default(),
});
let enter = self.unifier.add_ty(enter);
let exit = TypeEnum::TFunc(FunSignature {
args: vec![],
ret: self.unifier.get_dummy_var().0,
vars: HashMap::default(),
vars: VarMap::default(),
});
let exit = self.unifier.add_ty(exit);
let mut fields = HashMap::new();
@ -503,7 +503,7 @@ impl<'a> Fold<()> for Inferencer<'a> {
assert_eq!(*id, *id_var);
(*id, self.unifier.get_fresh_var_with_range(range, *name, *loc).0)
})
.collect::<HashMap<_, _>>();
.collect::<VarMap>();
Some(self.unifier.subst(self.primitives.option, &var_map).unwrap())
} else {
unreachable!("must be tobj")
@ -704,7 +704,7 @@ impl<'a> Inferencer<'a> {
.map(|(k, ty)| FuncArg { name: *k, ty: *ty, default_value: None })
.collect(),
ret,
vars: HashMap::default(),
vars: VarMap::default(),
};
let body = new_context.fold_expr(body)?;
new_context.unify(fun.ret, body.custom.unwrap(), &location)?;
@ -939,7 +939,7 @@ impl<'a> Inferencer<'a> {
},
],
ret,
vars: HashMap::new(),
vars: VarMap::new(),
}));
return Ok(Some(Located {
@ -996,7 +996,7 @@ impl<'a> Inferencer<'a> {
},
],
ret,
vars: HashMap::new(),
vars: VarMap::new(),
}));
return Ok(Some(Located {

View File

@ -75,70 +75,70 @@ impl TestEnvironment {
let int32 = unifier.add_ty(TypeEnum::TObj {
obj_id: PRIMITIVE_DEF_IDS.int32,
fields: HashMap::new(),
params: HashMap::new(),
params: VarMap::new(),
});
with_fields(&mut unifier, int32, |unifier, fields| {
let add_ty = unifier.add_ty(TypeEnum::TFunc(FunSignature {
args: vec![FuncArg { name: "other".into(), ty: int32, default_value: None }],
ret: int32,
vars: HashMap::new(),
vars: VarMap::new(),
}));
fields.insert("__add__".into(), (add_ty, false));
});
let int64 = unifier.add_ty(TypeEnum::TObj {
obj_id: PRIMITIVE_DEF_IDS.int64,
fields: HashMap::new(),
params: HashMap::new(),
params: VarMap::new(),
});
let float = unifier.add_ty(TypeEnum::TObj {
obj_id: PRIMITIVE_DEF_IDS.float,
fields: HashMap::new(),
params: HashMap::new(),
params: VarMap::new(),
});
let bool = unifier.add_ty(TypeEnum::TObj {
obj_id: PRIMITIVE_DEF_IDS.bool,
fields: HashMap::new(),
params: HashMap::new(),
params: VarMap::new(),
});
let none = unifier.add_ty(TypeEnum::TObj {
obj_id: PRIMITIVE_DEF_IDS.none,
fields: HashMap::new(),
params: HashMap::new(),
params: VarMap::new(),
});
let range = unifier.add_ty(TypeEnum::TObj {
obj_id: PRIMITIVE_DEF_IDS.range,
fields: HashMap::new(),
params: HashMap::new(),
params: VarMap::new(),
});
let str = unifier.add_ty(TypeEnum::TObj {
obj_id: PRIMITIVE_DEF_IDS.str,
fields: HashMap::new(),
params: HashMap::new(),
params: VarMap::new(),
});
let exception = unifier.add_ty(TypeEnum::TObj {
obj_id: PRIMITIVE_DEF_IDS.exception,
fields: HashMap::new(),
params: HashMap::new(),
params: VarMap::new(),
});
let uint32 = unifier.add_ty(TypeEnum::TObj {
obj_id: PRIMITIVE_DEF_IDS.uint32,
fields: HashMap::new(),
params: HashMap::new(),
params: VarMap::new(),
});
let uint64 = unifier.add_ty(TypeEnum::TObj {
obj_id: PRIMITIVE_DEF_IDS.uint64,
fields: HashMap::new(),
params: HashMap::new(),
params: VarMap::new(),
});
let option = unifier.add_ty(TypeEnum::TObj {
obj_id: PRIMITIVE_DEF_IDS.option,
fields: HashMap::new(),
params: HashMap::new(),
params: VarMap::new(),
});
let ndarray = unifier.add_ty(TypeEnum::TObj {
obj_id: PRIMITIVE_DEF_IDS.ndarray,
fields: HashMap::new(),
params: HashMap::new(),
params: VarMap::new(),
});
let primitives = PrimitiveStore {
int32,
@ -208,70 +208,70 @@ impl TestEnvironment {
let int32 = unifier.add_ty(TypeEnum::TObj {
obj_id: PRIMITIVE_DEF_IDS.int32,
fields: HashMap::new(),
params: HashMap::new(),
params: VarMap::new(),
});
with_fields(&mut unifier, int32, |unifier, fields| {
let add_ty = unifier.add_ty(TypeEnum::TFunc(FunSignature {
args: vec![FuncArg { name: "other".into(), ty: int32, default_value: None }],
ret: int32,
vars: HashMap::new(),
vars: VarMap::new(),
}));
fields.insert("__add__".into(), (add_ty, false));
});
let int64 = unifier.add_ty(TypeEnum::TObj {
obj_id: PRIMITIVE_DEF_IDS.int64,
fields: HashMap::new(),
params: HashMap::new(),
params: VarMap::new(),
});
let float = unifier.add_ty(TypeEnum::TObj {
obj_id: PRIMITIVE_DEF_IDS.float,
fields: HashMap::new(),
params: HashMap::new(),
params: VarMap::new(),
});
let bool = unifier.add_ty(TypeEnum::TObj {
obj_id: PRIMITIVE_DEF_IDS.bool,
fields: HashMap::new(),
params: HashMap::new(),
params: VarMap::new(),
});
let none = unifier.add_ty(TypeEnum::TObj {
obj_id: PRIMITIVE_DEF_IDS.none,
fields: HashMap::new(),
params: HashMap::new(),
params: VarMap::new(),
});
let range = unifier.add_ty(TypeEnum::TObj {
obj_id: PRIMITIVE_DEF_IDS.range,
fields: HashMap::new(),
params: HashMap::new(),
params: VarMap::new(),
});
let str = unifier.add_ty(TypeEnum::TObj {
obj_id: PRIMITIVE_DEF_IDS.str,
fields: HashMap::new(),
params: HashMap::new(),
params: VarMap::new(),
});
let exception = unifier.add_ty(TypeEnum::TObj {
obj_id: PRIMITIVE_DEF_IDS.exception,
fields: HashMap::new(),
params: HashMap::new(),
params: VarMap::new(),
});
let uint32 = unifier.add_ty(TypeEnum::TObj {
obj_id: PRIMITIVE_DEF_IDS.uint32,
fields: HashMap::new(),
params: HashMap::new(),
params: VarMap::new(),
});
let uint64 = unifier.add_ty(TypeEnum::TObj {
obj_id: PRIMITIVE_DEF_IDS.uint64,
fields: HashMap::new(),
params: HashMap::new(),
params: VarMap::new(),
});
let option = unifier.add_ty(TypeEnum::TObj {
obj_id: PRIMITIVE_DEF_IDS.option,
fields: HashMap::new(),
params: HashMap::new(),
params: VarMap::new(),
});
let ndarray = unifier.add_ty(TypeEnum::TObj {
obj_id: PRIMITIVE_DEF_IDS.ndarray,
fields: HashMap::new(),
params: HashMap::new(),
params: VarMap::new(),
});
identifier_mapping.insert("None".into(), none);
for (i, name) in ["int32", "int64", "float", "bool", "none", "range", "str", "Exception"]
@ -318,7 +318,7 @@ impl TestEnvironment {
let foo_ty = unifier.add_ty(TypeEnum::TObj {
obj_id: DefinitionId(defs + 1),
fields: [("a".into(), (v0, true))].iter().cloned().collect::<HashMap<_, _>>(),
params: [(id, v0)].iter().cloned().collect::<HashMap<_, _>>(),
params: [(id, v0)].iter().cloned().collect::<VarMap>(),
});
top_level_defs.push(
RwLock::new(TopLevelDef::Class {

View File

@ -1,5 +1,5 @@
use std::cell::RefCell;
use std::collections::HashMap;
use std::collections::{BTreeMap, HashMap};
use std::fmt::Display;
use std::rc::Rc;
use std::sync::{Arc, Mutex};
@ -25,7 +25,14 @@ pub type Type = UnificationKey;
pub struct CallId(pub(super) usize);
pub type Mapping<K, V = Type> = HashMap<K, V>;
type VarMap = Mapping<u32>;
/// A [`Mapping`] sorted by its key.
///
/// This type is recommended for mappings that should be stored and/or iterated by its sorted key.
pub type SortedMapping<K, V = Type> = BTreeMap<K, V>;
/// A [`BTreeMap`] storing the mapping between type variable ID and [unifier type][`Type`].
pub type VarMap = SortedMapping<u32>;
#[derive(Clone)]
pub struct Call {
@ -1276,12 +1283,12 @@ impl Unifier {
fn subst_map<K>(
&mut self,
map: &Mapping<K>,
map: &SortedMapping<K>,
mapping: &VarMap,
cache: &mut HashMap<Type, Option<Type>>,
) -> Option<Mapping<K>>
) -> Option<SortedMapping<K>>
where
K: std::hash::Hash + Eq + Clone,
K: Ord + Eq + Clone,
{
let mut map2 = None;
for (k, v) in map {

View File

@ -45,9 +45,9 @@ impl Unifier {
}
}
fn map_eq<K>(&mut self, map1: &Mapping<K>, map2: &Mapping<K>) -> bool
fn map_eq<K>(&mut self, map1: &SortedMapping<K>, map2: &SortedMapping<K>) -> bool
where
K: std::hash::Hash + Eq + Clone,
K: Ord + Eq + Clone,
{
if map1.len() != map2.len() {
return false;
@ -91,7 +91,7 @@ impl TestEnvironment {
unifier.add_ty(TypeEnum::TObj {
obj_id: DefinitionId(0),
fields: HashMap::new(),
params: HashMap::new(),
params: VarMap::new(),
}),
);
type_mapping.insert(
@ -99,7 +99,7 @@ impl TestEnvironment {
unifier.add_ty(TypeEnum::TObj {
obj_id: DefinitionId(1),
fields: HashMap::new(),
params: HashMap::new(),
params: VarMap::new(),
}),
);
type_mapping.insert(
@ -107,7 +107,7 @@ impl TestEnvironment {
unifier.add_ty(TypeEnum::TObj {
obj_id: DefinitionId(2),
fields: HashMap::new(),
params: HashMap::new(),
params: VarMap::new(),
}),
);
let (v0, id) = unifier.get_dummy_var();
@ -116,7 +116,7 @@ impl TestEnvironment {
unifier.add_ty(TypeEnum::TObj {
obj_id: DefinitionId(3),
fields: [("a".into(), (v0, true))].iter().cloned().collect::<HashMap<_, _>>(),
params: [(id, v0)].iter().cloned().collect::<HashMap<_, _>>(),
params: [(id, v0)].iter().cloned().collect::<VarMap>(),
}),
);
@ -363,7 +363,7 @@ fn test_virtual() {
let fun = env.unifier.add_ty(TypeEnum::TFunc(FunSignature {
args: vec![],
ret: int,
vars: HashMap::new(),
vars: VarMap::new(),
}));
let bar = env.unifier.add_ty(TypeEnum::TObj {
obj_id: DefinitionId(5),
@ -371,7 +371,7 @@ fn test_virtual() {
.iter()
.cloned()
.collect::<HashMap<StrRef, _>>(),
params: HashMap::new(),
params: VarMap::new(),
});
let v0 = env.unifier.get_dummy_var().0;
let v1 = env.unifier.get_dummy_var().0;

View File

@ -17,12 +17,14 @@ use nac3core::{
},
symbol_resolver::SymbolResolver,
toplevel::{
composer::TopLevelComposer, helper::parse_parameter_default_value, type_annotation::*,
composer::{ComposerConfig, TopLevelComposer},
helper::parse_parameter_default_value,
type_annotation::*,
TopLevelDef,
},
typecheck::{
type_inferencer::PrimitiveStore,
typedef::{FunSignature, Type, Unifier},
typedef::{FunSignature, Type, Unifier, VarMap},
},
};
use nac3parser::{
@ -32,7 +34,6 @@ use nac3parser::{
mod basic_symbol_resolver;
use basic_symbol_resolver::*;
use nac3core::toplevel::composer::ComposerConfig;
/// Command-line argument parser definition.
#[derive(Parser)]
@ -345,7 +346,7 @@ fn main() {
}
}
let signature = FunSignature { args: vec![], ret: primitive.int32, vars: HashMap::new() };
let signature = FunSignature { args: vec![], ret: primitive.int32, vars: VarMap::new() };
let mut store = ConcreteTypeStore::new();
let mut cache = HashMap::new();
let signature = store.from_signature(&mut composer.unifier, &primitive, &signature, &mut cache);