Compare commits
1 Commits
d03ad8a1c4
...
9a8342d6d4
Author | SHA1 | Date |
---|---|---|
David Mak | 9a8342d6d4 |
|
@ -616,6 +616,7 @@ name = "nac3core"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"crossbeam",
|
"crossbeam",
|
||||||
|
"indexmap 2.2.5",
|
||||||
"indoc",
|
"indoc",
|
||||||
"inkwell",
|
"inkwell",
|
||||||
"insta",
|
"insta",
|
||||||
|
|
|
@ -10,7 +10,7 @@ use nac3core::{
|
||||||
},
|
},
|
||||||
typecheck::{
|
typecheck::{
|
||||||
type_inferencer::PrimitiveStore,
|
type_inferencer::PrimitiveStore,
|
||||||
typedef::{SortedVarMap, Type, TypeEnum, Unifier},
|
typedef::{Type, TypeEnum, Unifier, VarMap},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use nac3parser::ast::{self, StrRef};
|
use nac3parser::ast::{self, StrRef};
|
||||||
|
@ -519,7 +519,7 @@ impl InnerResolver {
|
||||||
.iter()
|
.iter()
|
||||||
.zip(args.iter())
|
.zip(args.iter())
|
||||||
.map(|((id, _), ty)| (*id, *ty))
|
.map(|((id, _), ty)| (*id, *ty))
|
||||||
.collect::<SortedVarMap>()
|
.collect::<VarMap>()
|
||||||
};
|
};
|
||||||
Ok(Ok((unifier.subst(origin_ty, &subst).unwrap_or(origin_ty), true)))
|
Ok(Ok((unifier.subst(origin_ty, &subst).unwrap_or(origin_ty), true)))
|
||||||
}
|
}
|
||||||
|
@ -722,7 +722,7 @@ impl InnerResolver {
|
||||||
assert_eq!(*id, *id_var);
|
assert_eq!(*id, *id_var);
|
||||||
(*id, unifier.get_fresh_var_with_range(range, *name, *loc).0)
|
(*id, unifier.get_fresh_var_with_range(range, *name, *loc).0)
|
||||||
})
|
})
|
||||||
.collect::<SortedVarMap>();
|
.collect::<VarMap>();
|
||||||
return Ok(Ok(unifier.subst(primitives.option, &var_map).unwrap()))
|
return Ok(Ok(unifier.subst(primitives.option, &var_map).unwrap()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -734,7 +734,7 @@ impl InnerResolver {
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let new_var_map: SortedVarMap = 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);
|
let res = unifier.subst(extracted_ty, &new_var_map).unwrap_or(extracted_ty);
|
||||||
Ok(Ok(res))
|
Ok(Ok(res))
|
||||||
}
|
}
|
||||||
|
@ -751,7 +751,7 @@ impl InnerResolver {
|
||||||
assert_eq!(*id, *id_var);
|
assert_eq!(*id, *id_var);
|
||||||
(*id, unifier.get_fresh_var_with_range(range, *name, *loc).0)
|
(*id, unifier.get_fresh_var_with_range(range, *name, *loc).0)
|
||||||
})
|
})
|
||||||
.collect::<SortedVarMap>();
|
.collect::<VarMap>();
|
||||||
let mut instantiate_obj = || {
|
let mut instantiate_obj = || {
|
||||||
// loop through non-function fields of the class to get the instantiated value
|
// loop through non-function fields of the class to get the instantiated value
|
||||||
for field in fields {
|
for field in fields {
|
||||||
|
|
|
@ -7,6 +7,7 @@ edition = "2021"
|
||||||
[dependencies]
|
[dependencies]
|
||||||
itertools = "0.12"
|
itertools = "0.12"
|
||||||
crossbeam = "0.8"
|
crossbeam = "0.8"
|
||||||
|
indexmap = "2.2"
|
||||||
parking_lot = "0.12"
|
parking_lot = "0.12"
|
||||||
rayon = "1.8"
|
rayon = "1.8"
|
||||||
nac3parser = { path = "../nac3parser" }
|
nac3parser = { path = "../nac3parser" }
|
||||||
|
|
|
@ -9,6 +9,7 @@ use crate::{
|
||||||
|
|
||||||
use nac3parser::ast::StrRef;
|
use nac3parser::ast::StrRef;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use indexmap::IndexMap;
|
||||||
|
|
||||||
pub struct ConcreteTypeStore {
|
pub struct ConcreteTypeStore {
|
||||||
store: Vec<ConcreteTypeEnum>,
|
store: Vec<ConcreteTypeEnum>,
|
||||||
|
@ -50,7 +51,7 @@ pub enum ConcreteTypeEnum {
|
||||||
TObj {
|
TObj {
|
||||||
obj_id: DefinitionId,
|
obj_id: DefinitionId,
|
||||||
fields: HashMap<StrRef, (ConcreteType, bool)>,
|
fields: HashMap<StrRef, (ConcreteType, bool)>,
|
||||||
params: Vec<(u32, ConcreteType)>,
|
params: IndexMap<u32, ConcreteType>,
|
||||||
},
|
},
|
||||||
TVirtual {
|
TVirtual {
|
||||||
ty: ConcreteType,
|
ty: ConcreteType,
|
||||||
|
|
|
@ -20,7 +20,7 @@ use crate::{
|
||||||
TopLevelDef,
|
TopLevelDef,
|
||||||
},
|
},
|
||||||
typecheck::{
|
typecheck::{
|
||||||
typedef::{FunSignature, FuncArg, SortedVarMap, Type, TypeEnum, Unifier},
|
typedef::{FunSignature, FuncArg, Type, TypeEnum, Unifier, VarMap},
|
||||||
magic_methods::{binop_name, binop_assign_name},
|
magic_methods::{binop_name, binop_assign_name},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -42,7 +42,7 @@ use super::{CodeGenerator, llvm_intrinsics::call_memcpy_generic, need_sret};
|
||||||
pub fn get_subst_key(
|
pub fn get_subst_key(
|
||||||
unifier: &mut Unifier,
|
unifier: &mut Unifier,
|
||||||
obj: Option<Type>,
|
obj: Option<Type>,
|
||||||
fun_vars: &SortedVarMap,
|
fun_vars: &VarMap,
|
||||||
filter: Option<&Vec<u32>>,
|
filter: Option<&Vec<u32>>,
|
||||||
) -> String {
|
) -> String {
|
||||||
let mut vars = obj
|
let mut vars = obj
|
||||||
|
@ -50,7 +50,7 @@ pub fn get_subst_key(
|
||||||
let TypeEnum::TObj { params, .. } = &*unifier.get_ty(ty) else {
|
let TypeEnum::TObj { params, .. } = &*unifier.get_ty(ty) else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
};
|
};
|
||||||
params.to_sorted()
|
params.clone()
|
||||||
})
|
})
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
vars.extend(fun_vars);
|
vars.extend(fun_vars);
|
||||||
|
@ -86,7 +86,7 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> {
|
||||||
fun: &FunSignature,
|
fun: &FunSignature,
|
||||||
filter: Option<&Vec<u32>>,
|
filter: Option<&Vec<u32>>,
|
||||||
) -> String {
|
) -> String {
|
||||||
get_subst_key(&mut self.unifier, obj, &fun.vars.to_sorted(), filter)
|
get_subst_key(&mut self.unifier, obj, &fun.vars, filter)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_attr_index(&mut self, ty: Type, attr: StrRef) -> usize {
|
pub fn get_attr_index(&mut self, ty: Type, attr: StrRef) -> usize {
|
||||||
|
@ -644,7 +644,7 @@ pub fn gen_func_instance<'ctx>(
|
||||||
let mut filter = var_id.clone();
|
let mut filter = var_id.clone();
|
||||||
if let Some((obj_ty, _)) = &obj {
|
if let Some((obj_ty, _)) = &obj {
|
||||||
if let TypeEnum::TObj { params, .. } = &*ctx.unifier.get_ty(*obj_ty) {
|
if let TypeEnum::TObj { params, .. } = &*ctx.unifier.get_ty(*obj_ty) {
|
||||||
filter.extend(params.ids());
|
filter.extend(params.keys());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let key = ctx.get_subst_key(obj.as_ref().map(|a| a.0), sign, Some(&filter));
|
let key = ctx.get_subst_key(obj.as_ref().map(|a| a.0), sign, Some(&filter));
|
||||||
|
|
|
@ -527,12 +527,12 @@ pub fn parse_type_annotation<T>(
|
||||||
let mut fields = fields
|
let mut fields = fields
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(attr, ty, is_mutable)| {
|
.map(|(attr, ty, is_mutable)| {
|
||||||
let ty = unifier.subst(*ty, &subst.to_sorted()).unwrap_or(*ty);
|
let ty = unifier.subst(*ty, &subst).unwrap_or(*ty);
|
||||||
(*attr, (ty, *is_mutable))
|
(*attr, (ty, *is_mutable))
|
||||||
})
|
})
|
||||||
.collect::<HashMap<_, _>>();
|
.collect::<HashMap<_, _>>();
|
||||||
fields.extend(methods.iter().map(|(attr, ty, _)| {
|
fields.extend(methods.iter().map(|(attr, ty, _)| {
|
||||||
let ty = unifier.subst(*ty, &subst.to_sorted()).unwrap_or(*ty);
|
let ty = unifier.subst(*ty, &subst).unwrap_or(*ty);
|
||||||
(*attr, (ty, false))
|
(*attr, (ty, false))
|
||||||
}));
|
}));
|
||||||
Ok(unifier.add_ty(TypeEnum::TObj { obj_id, fields, params: subst }))
|
Ok(unifier.add_ty(TypeEnum::TObj { obj_id, fields, params: subst }))
|
||||||
|
|
|
@ -6,7 +6,7 @@ use crate::{
|
||||||
symbol_resolver::SymbolValue,
|
symbol_resolver::SymbolValue,
|
||||||
typecheck::{
|
typecheck::{
|
||||||
type_inferencer::{FunctionData, Inferencer},
|
type_inferencer::{FunctionData, Inferencer},
|
||||||
typedef::{SortedVarMap, VarMap},
|
typedef::VarMap,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -779,7 +779,7 @@ impl TopLevelComposer {
|
||||||
let mut new_fields = HashMap::new();
|
let mut new_fields = HashMap::new();
|
||||||
let mut need_subst = false;
|
let mut need_subst = false;
|
||||||
for (name, (ty, mutable)) in fields {
|
for (name, (ty, mutable)) in fields {
|
||||||
let substituted = unifier.subst(*ty, ¶ms.to_sorted());
|
let substituted = unifier.subst(*ty, params);
|
||||||
need_subst |= substituted.is_some();
|
need_subst |= substituted.is_some();
|
||||||
new_fields.insert(*name, (substituted.unwrap_or(*ty), *mutable));
|
new_fields.insert(*name, (substituted.unwrap_or(*ty), *mutable));
|
||||||
}
|
}
|
||||||
|
@ -1508,7 +1508,7 @@ impl TopLevelComposer {
|
||||||
} = &mut *def.write() {
|
} = &mut *def.write() {
|
||||||
if let TypeEnum::TFunc(FunSignature { args, ret, vars }) =
|
if let TypeEnum::TFunc(FunSignature { args, ret, vars }) =
|
||||||
unifier.get_ty(*signature).as_ref() {
|
unifier.get_ty(*signature).as_ref() {
|
||||||
let new_var_ids = vars.types().map(|v| match &*unifier.get_ty(*v) {
|
let new_var_ids = vars.values().map(|v| match &*unifier.get_ty(*v) {
|
||||||
TypeEnum::TVar{id, ..} => *id,
|
TypeEnum::TVar{id, ..} => *id,
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}).collect_vec();
|
}).collect_vec();
|
||||||
|
@ -1516,7 +1516,7 @@ impl TopLevelComposer {
|
||||||
let new_signature = FunSignature {
|
let new_signature = FunSignature {
|
||||||
args: args.clone(),
|
args: args.clone(),
|
||||||
ret: *ret,
|
ret: *ret,
|
||||||
vars: new_var_ids.iter().zip(vars.types()).map(|(id, v)| (*id, *v)).collect(),
|
vars: new_var_ids.iter().zip(vars.values()).map(|(id, v)| (*id, *v)).collect(),
|
||||||
};
|
};
|
||||||
unifier.unification_table.set_value(*signature, Rc::new(TypeEnum::TFunc(new_signature)));
|
unifier.unification_table.set_value(*signature, Rc::new(TypeEnum::TFunc(new_signature)));
|
||||||
*var_id = new_var_ids;
|
*var_id = new_var_ids;
|
||||||
|
@ -1612,7 +1612,7 @@ impl TopLevelComposer {
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor_args.extend_from_slice(args);
|
constructor_args.extend_from_slice(args);
|
||||||
type_vars.extend(vars.to_sorted());
|
type_vars.extend(vars);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(constructor_args, type_vars)
|
(constructor_args, type_vars)
|
||||||
|
@ -1738,7 +1738,7 @@ impl TopLevelComposer {
|
||||||
let (type_var_subst_comb, no_range_vars) = {
|
let (type_var_subst_comb, no_range_vars) = {
|
||||||
let mut no_ranges: Vec<Type> = Vec::new();
|
let mut no_ranges: Vec<Type> = Vec::new();
|
||||||
let var_combs = vars
|
let var_combs = vars
|
||||||
.types()
|
.values()
|
||||||
.map(|ty| {
|
.map(|ty| {
|
||||||
unifier.get_instantiations(*ty).unwrap_or_else(|| {
|
unifier.get_instantiations(*ty).unwrap_or_else(|| {
|
||||||
let TypeEnum::TVar { name, loc, is_const_generic: false, .. } = &*unifier.get_ty(*ty) else {
|
let TypeEnum::TVar { name, loc, is_const_generic: false, .. } = &*unifier.get_ty(*ty) else {
|
||||||
|
@ -1752,13 +1752,13 @@ impl TopLevelComposer {
|
||||||
})
|
})
|
||||||
.multi_cartesian_product()
|
.multi_cartesian_product()
|
||||||
.collect_vec();
|
.collect_vec();
|
||||||
let mut result: Vec<SortedVarMap> = Vec::default();
|
let mut result: Vec<VarMap> = Vec::default();
|
||||||
for comb in var_combs {
|
for comb in var_combs {
|
||||||
result.push(vars.ids().copied().zip(comb).collect());
|
result.push(vars.keys().copied().zip(comb).collect());
|
||||||
}
|
}
|
||||||
// NOTE: if is empty, means no type var, append a empty subst, ok to do this?
|
// NOTE: if is empty, means no type var, append a empty subst, ok to do this?
|
||||||
if result.is_empty() {
|
if result.is_empty() {
|
||||||
result.push(SortedVarMap::new());
|
result.push(VarMap::new());
|
||||||
}
|
}
|
||||||
(result, no_ranges)
|
(result, no_ranges)
|
||||||
};
|
};
|
||||||
|
@ -1798,7 +1798,7 @@ impl TopLevelComposer {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect::<SortedVarMap>()
|
.collect::<VarMap>()
|
||||||
};
|
};
|
||||||
unifier.subst(self_type, &subst_for_self).unwrap_or(self_type)
|
unifier.subst(self_type, &subst_for_self).unwrap_or(self_type)
|
||||||
})
|
})
|
||||||
|
@ -1930,7 +1930,7 @@ impl TopLevelComposer {
|
||||||
}
|
}
|
||||||
|
|
||||||
instance_to_stmt.insert(
|
instance_to_stmt.insert(
|
||||||
get_subst_key(unifier, self_type, &subst, Some(&vars.ids().copied().collect())),
|
get_subst_key(unifier, self_type, &subst, Some(&vars.keys().copied().collect())),
|
||||||
FunInstance {
|
FunInstance {
|
||||||
body: Arc::new(fun_body),
|
body: Arc::new(fun_body),
|
||||||
unifier_id: 0,
|
unifier_id: 0,
|
||||||
|
|
|
@ -8,7 +8,7 @@ use std::{
|
||||||
|
|
||||||
use super::codegen::CodeGenContext;
|
use super::codegen::CodeGenContext;
|
||||||
use super::typecheck::type_inferencer::PrimitiveStore;
|
use super::typecheck::type_inferencer::PrimitiveStore;
|
||||||
use super::typecheck::typedef::{FunSignature, FuncArg, SharedUnifier, Type, TypeEnum, Unifier, SortedVarMap};
|
use super::typecheck::typedef::{FunSignature, FuncArg, SharedUnifier, Type, TypeEnum, Unifier, VarMap};
|
||||||
use crate::{
|
use crate::{
|
||||||
codegen::CodeGenerator,
|
codegen::CodeGenerator,
|
||||||
symbol_resolver::{SymbolResolver, ValueEnum},
|
symbol_resolver::{SymbolResolver, ValueEnum},
|
||||||
|
@ -76,7 +76,7 @@ impl Debug for GenCall {
|
||||||
pub struct FunInstance {
|
pub struct FunInstance {
|
||||||
pub body: Arc<Vec<Stmt<Option<Type>>>>,
|
pub body: Arc<Vec<Stmt<Option<Type>>>>,
|
||||||
pub calls: Arc<HashMap<CodeLocation, CallId>>,
|
pub calls: Arc<HashMap<CodeLocation, CallId>>,
|
||||||
pub subst: SortedVarMap,
|
pub subst: VarMap,
|
||||||
pub unifier_id: usize,
|
pub unifier_id: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ use crate::{
|
||||||
toplevel::helper::PRIMITIVE_DEF_IDS,
|
toplevel::helper::PRIMITIVE_DEF_IDS,
|
||||||
typecheck::{
|
typecheck::{
|
||||||
type_inferencer::PrimitiveStore,
|
type_inferencer::PrimitiveStore,
|
||||||
typedef::{Type, TypeEnum, Unifier, SortedVarMap},
|
typedef::{Type, TypeEnum, Unifier, VarMap},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ pub fn make_ndarray_ty(
|
||||||
.collect_vec();
|
.collect_vec();
|
||||||
debug_assert_eq!(tvar_ids.len(), 2);
|
debug_assert_eq!(tvar_ids.len(), 2);
|
||||||
|
|
||||||
let mut tvar_subst = SortedVarMap::new();
|
let mut tvar_subst = VarMap::new();
|
||||||
if let Some(dtype) = dtype {
|
if let Some(dtype) = dtype {
|
||||||
tvar_subst.insert(tvar_ids[0], dtype);
|
tvar_subst.insert(tvar_ids[0], dtype);
|
||||||
}
|
}
|
||||||
|
|
|
@ -483,13 +483,13 @@ pub fn get_type_from_type_annotation_kinds(
|
||||||
let mut tobj_fields = methods
|
let mut tobj_fields = methods
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(name, ty, _)| {
|
.map(|(name, ty, _)| {
|
||||||
let subst_ty = unifier.subst(*ty, &subst.to_sorted()).unwrap_or(*ty);
|
let subst_ty = unifier.subst(*ty, &subst).unwrap_or(*ty);
|
||||||
// methods are immutable
|
// methods are immutable
|
||||||
(*name, (subst_ty, false))
|
(*name, (subst_ty, false))
|
||||||
})
|
})
|
||||||
.collect::<HashMap<_, _>>();
|
.collect::<HashMap<_, _>>();
|
||||||
tobj_fields.extend(fields.iter().map(|(name, ty, mutability)| {
|
tobj_fields.extend(fields.iter().map(|(name, ty, mutability)| {
|
||||||
let subst_ty = unifier.subst(*ty, &subst.to_sorted()).unwrap_or(*ty);
|
let subst_ty = unifier.subst(*ty, &subst).unwrap_or(*ty);
|
||||||
(*name, (subst_ty, *mutability))
|
(*name, (subst_ty, *mutability))
|
||||||
}));
|
}));
|
||||||
let need_subst = !subst.is_empty();
|
let need_subst = !subst.is_empty();
|
||||||
|
|
|
@ -3,7 +3,7 @@ use std::convert::{From, TryInto};
|
||||||
use std::iter::once;
|
use std::iter::once;
|
||||||
use std::{cell::RefCell, sync::Arc};
|
use std::{cell::RefCell, sync::Arc};
|
||||||
|
|
||||||
use super::typedef::{Call, FunSignature, FuncArg, RecordField, SortedVarMap, Type, TypeEnum, Unifier, VarMap};
|
use super::typedef::{Call, FunSignature, FuncArg, RecordField, Type, TypeEnum, Unifier, VarMap};
|
||||||
use super::{magic_methods::*, typedef::CallId};
|
use super::{magic_methods::*, typedef::CallId};
|
||||||
use crate::{
|
use crate::{
|
||||||
symbol_resolver::{SymbolResolver, SymbolValue},
|
symbol_resolver::{SymbolResolver, SymbolValue},
|
||||||
|
@ -503,7 +503,7 @@ impl<'a> Fold<()> for Inferencer<'a> {
|
||||||
assert_eq!(*id, *id_var);
|
assert_eq!(*id, *id_var);
|
||||||
(*id, self.unifier.get_fresh_var_with_range(range, *name, *loc).0)
|
(*id, self.unifier.get_fresh_var_with_range(range, *name, *loc).0)
|
||||||
})
|
})
|
||||||
.collect::<SortedVarMap>();
|
.collect::<VarMap>();
|
||||||
Some(self.unifier.subst(self.primitives.option, &var_map).unwrap())
|
Some(self.unifier.subst(self.primitives.option, &var_map).unwrap())
|
||||||
} else {
|
} else {
|
||||||
unreachable!("must be tobj")
|
unreachable!("must be tobj")
|
||||||
|
|
|
@ -5,6 +5,7 @@ use std::rc::Rc;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use std::{borrow::Cow, collections::HashSet};
|
use std::{borrow::Cow, collections::HashSet};
|
||||||
use std::iter::zip;
|
use std::iter::zip;
|
||||||
|
use indexmap::IndexMap;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
|
||||||
use nac3parser::ast::{Location, StrRef};
|
use nac3parser::ast::{Location, StrRef};
|
||||||
|
@ -25,207 +26,10 @@ pub type Type = UnificationKey;
|
||||||
pub struct CallId(pub(super) usize);
|
pub struct CallId(pub(super) usize);
|
||||||
|
|
||||||
pub type Mapping<K, V = Type> = HashMap<K, V>;
|
pub type Mapping<K, V = Type> = HashMap<K, V>;
|
||||||
|
pub type IndexMapping<K, V = Type> = IndexMap<K, V>;
|
||||||
|
|
||||||
/// A sequenced collection storing type variable IDs and their [unifier types][Type], preserving the
|
/// The mapping between type variable ID and [unifier type][`Type`].
|
||||||
/// order of type variables as it appears in the generic type or function declaration. This type
|
pub type VarMap = IndexMapping<u32>;
|
||||||
/// also guarantees the uniqueness of type variable IDs, i.e. only one type variable with the same
|
|
||||||
/// ID will be present in the map at all times.
|
|
||||||
#[derive(Clone, Default, PartialEq, Eq, Debug, Hash)]
|
|
||||||
pub struct VarMap {
|
|
||||||
var_ids: Vec<u32>,
|
|
||||||
var_tys: BTreeMap<u32, Type>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl VarMap {
|
|
||||||
/// Creates a new, empty [`VarMap`].
|
|
||||||
#[must_use]
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self::default()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the number of elements in this instance.
|
|
||||||
#[must_use]
|
|
||||||
pub fn len(&self) -> usize {
|
|
||||||
self.var_ids.len()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns `true` if this instance contains no elements.
|
|
||||||
#[must_use]
|
|
||||||
pub fn is_empty(&self) -> bool {
|
|
||||||
self.var_ids.is_empty()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates a consuming iterator visiting all entries of this instance as it appears in
|
|
||||||
/// declaration order.
|
|
||||||
///
|
|
||||||
/// See [`IntoIterator::into_iter`].
|
|
||||||
///
|
|
||||||
/// Implementation Note: This function should be implemented as part of [`IntoIterator`], but
|
|
||||||
/// [`impl_trait_in_assoc_type`](https://github.com/rust-lang/rust/issues/63063) is not
|
|
||||||
/// stabilized.
|
|
||||||
fn into_iter(self) -> impl Iterator<Item=(u32, Type)> {
|
|
||||||
self.var_tys
|
|
||||||
.into_iter()
|
|
||||||
.sorted_by_key(|(id, _)| self.var_ids.iter().position(|var_id| id == var_id).unwrap())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns an iterator over the entries of this instance as it appears in declaration order.
|
|
||||||
pub fn iter(&self) -> impl Iterator<Item=(&u32, &Type)> {
|
|
||||||
self.var_tys
|
|
||||||
.iter()
|
|
||||||
.sorted_by_key(|(id, _)| self.var_ids.iter().position(|var_id| *id == var_id).unwrap())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns an iterator that allows modifying each value as it appears in declaration order.
|
|
||||||
pub fn iter_mut(&mut self) -> impl Iterator<Item=(&u32, &mut Type)> {
|
|
||||||
self.var_tys
|
|
||||||
.iter_mut()
|
|
||||||
.sorted_by_key(|(id, _)| self.var_ids.iter().position(|var_id| *id == var_id).unwrap())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns an iterator over the type variable IDs as it appears in declaration order.
|
|
||||||
pub fn ids(&self) -> impl Iterator<Item=&u32> {
|
|
||||||
self.var_ids.iter()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns an iterator over the types of type variables as it appears in declaration order.
|
|
||||||
pub fn types(&self) -> impl Iterator<Item=&Type> {
|
|
||||||
self.iter().map(|(_, ty)| ty)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns `true` if this instance contains the given type variable ID.
|
|
||||||
#[must_use]
|
|
||||||
pub fn contains_id(&self, var_id: &u32) -> bool {
|
|
||||||
self.get_key_value(var_id).is_some()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns a reference to the type corresponding to the type variable ID.
|
|
||||||
#[must_use]
|
|
||||||
pub fn get(&self, var_id: &u32) -> Option<&Type> {
|
|
||||||
self.get_key_value(var_id).map(|(_, ty)| ty)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns a mutable reference to the type corresponding to the type variable ID.
|
|
||||||
pub fn get_mut(&mut self, var_id: &u32) -> Option<&mut Type> {
|
|
||||||
self.var_tys.get_mut(var_id)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns a reference to the pair of type variable ID and type corresponding to the ID.
|
|
||||||
#[must_use]
|
|
||||||
pub fn get_key_value(&self, var_id: &u32) -> Option<(&u32, &Type)> {
|
|
||||||
self.var_tys.get_key_value(var_id)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns references to the type variable ID and associated type at the given declaration
|
|
||||||
/// `index`.
|
|
||||||
#[must_use]
|
|
||||||
pub fn index(&self, index: usize) -> Option<(&u32, &Type)> {
|
|
||||||
self.iter().nth(index)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns mutable references to the type variable ID and associated type at the given
|
|
||||||
/// declaration `index`.
|
|
||||||
pub fn index_mut(&mut self, index: usize) -> Option<(&u32, &mut Type)> {
|
|
||||||
self.iter_mut().nth(index)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates a [`SortedVarMap`] containing all entries in this instance.
|
|
||||||
#[must_use]
|
|
||||||
pub fn to_sorted(&self) -> SortedVarMap {
|
|
||||||
self.into()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Inserts a type variable mapping into this instance.
|
|
||||||
///
|
|
||||||
/// If the type variable ID already exists, the `ty` associated with the type variable will be
|
|
||||||
/// replaced.
|
|
||||||
pub fn insert(&mut self, var_id: u32, ty: Type) -> Option<Type> {
|
|
||||||
self.insert_impl(var_id, ty, None)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Inserts a type variable mapping into this instance at the given `index`.
|
|
||||||
///
|
|
||||||
/// If the type variable ID already exists, the `ty` associated with the type variable will be
|
|
||||||
/// replaced.
|
|
||||||
pub fn insert_at(&mut self, var_id: u32, ty: Type, index: usize) -> Option<Type> {
|
|
||||||
self.insert_impl(var_id, ty, Some(index))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl VarMap {
|
|
||||||
fn insert_impl(&mut self, var_id: u32, ty: Type, index: Option<usize>) -> Option<Type> {
|
|
||||||
let old = self.var_tys.insert(var_id, ty);
|
|
||||||
if old.is_none() {
|
|
||||||
if let Some(index) = index {
|
|
||||||
self.var_ids.insert(index, var_id);
|
|
||||||
} else {
|
|
||||||
self.var_ids.push(var_id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
assert_eq!(self.var_ids.len(), self.var_tys.len());
|
|
||||||
|
|
||||||
old
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Extend<(u32, Type)> for VarMap {
|
|
||||||
fn extend<T: IntoIterator<Item=(u32, Type)>>(&mut self, iter: T) {
|
|
||||||
iter.into_iter().for_each(move |(k, v)| {
|
|
||||||
self.insert(k, v);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Extend<&'a (u32, Type)> for VarMap {
|
|
||||||
fn extend<T: IntoIterator<Item=&'a (u32, Type)>>(&mut self, iter: T) {
|
|
||||||
iter.into_iter().for_each(move |(k, v)| {
|
|
||||||
self.insert(*k, *v);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<const N: usize> From<[(u32, Type); N]> for VarMap {
|
|
||||||
fn from(value: [(u32, Type); N]) -> Self {
|
|
||||||
if N == 0 {
|
|
||||||
return VarMap::new()
|
|
||||||
}
|
|
||||||
|
|
||||||
value.into_iter().collect()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FromIterator<(u32, Type)> for VarMap {
|
|
||||||
fn from_iter<T: IntoIterator<Item=(u32, Type)>>(iter: T) -> Self {
|
|
||||||
let vars: Vec<(u32, Type)> = iter.into_iter().collect();
|
|
||||||
let var_ids = vars.iter()
|
|
||||||
.map(|(id, _)| *id)
|
|
||||||
.unique()
|
|
||||||
.collect();
|
|
||||||
let var_tys = vars.into_iter().collect();
|
|
||||||
|
|
||||||
Self { var_ids, var_tys }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A [mapping][`Mapping`] between type variable IDs and [unifier type][`Type`].
|
|
||||||
///
|
|
||||||
/// As opposed to [`VarMap`], this type does not preserve the order of type variables as it appears
|
|
||||||
/// in the generic declaration. As such, this type should only be used when lookup operations should
|
|
||||||
/// be prioritized *and* the declaration order of type variables does not matter.
|
|
||||||
pub type SortedVarMap = Mapping<u32>;
|
|
||||||
|
|
||||||
impl From<VarMap> for SortedVarMap {
|
|
||||||
fn from(value: VarMap) -> Self {
|
|
||||||
value.var_tys.into_iter().collect()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<&VarMap> for SortedVarMap {
|
|
||||||
fn from(value: &VarMap) -> Self {
|
|
||||||
value.var_tys.iter().map(|(id, ty)| (*id, *ty)).collect()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Call {
|
pub struct Call {
|
||||||
|
@ -679,7 +483,7 @@ impl Unifier {
|
||||||
|
|
||||||
TTuple { ty } => ty.iter().all(|ty| self.is_concrete(*ty, allowed_typevars)),
|
TTuple { ty } => ty.iter().all(|ty| self.is_concrete(*ty, allowed_typevars)),
|
||||||
TObj { params: vars, .. } => {
|
TObj { params: vars, .. } => {
|
||||||
vars.types().all(|ty| self.is_concrete(*ty, allowed_typevars))
|
vars.values().all(|ty| self.is_concrete(*ty, allowed_typevars))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1342,7 +1146,7 @@ impl Unifier {
|
||||||
fn instantiate_fun(&mut self, ty: Type, fun: &FunSignature) -> Type {
|
fn instantiate_fun(&mut self, ty: Type, fun: &FunSignature) -> Type {
|
||||||
let mut instantiated = true;
|
let mut instantiated = true;
|
||||||
let mut vars = Vec::new();
|
let mut vars = Vec::new();
|
||||||
for (k, v) in fun.vars.iter() {
|
for (k, v) in &fun.vars {
|
||||||
if let TypeEnum::TVar { id, name, loc, range, .. } =
|
if let TypeEnum::TVar { id, name, loc, range, .. } =
|
||||||
self.unification_table.probe_value(*v).as_ref()
|
self.unification_table.probe_value(*v).as_ref()
|
||||||
{
|
{
|
||||||
|
@ -1372,14 +1176,14 @@ impl Unifier {
|
||||||
/// If this returns Some(T), T would be the substituted type.
|
/// If this returns Some(T), T would be the substituted type.
|
||||||
/// If this returns None, the result type would be the original type
|
/// If this returns None, the result type would be the original type
|
||||||
/// (no substitution has to be done).
|
/// (no substitution has to be done).
|
||||||
pub fn subst(&mut self, a: Type, mapping: &SortedVarMap) -> Option<Type> {
|
pub fn subst(&mut self, a: Type, mapping: &VarMap) -> Option<Type> {
|
||||||
self.subst_impl(a, mapping, &mut HashMap::new())
|
self.subst_impl(a, mapping, &mut HashMap::new())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn subst_impl(
|
fn subst_impl(
|
||||||
&mut self,
|
&mut self,
|
||||||
a: Type,
|
a: Type,
|
||||||
mapping: &SortedVarMap,
|
mapping: &VarMap,
|
||||||
cache: &mut HashMap<Type, Option<Type>>,
|
cache: &mut HashMap<Type, Option<Type>>,
|
||||||
) -> Option<Type> {
|
) -> Option<Type> {
|
||||||
let cached = cache.get_mut(&a);
|
let cached = cache.get_mut(&a);
|
||||||
|
@ -1422,7 +1226,7 @@ impl Unifier {
|
||||||
// If the mapping does not contain any type variables in the
|
// If the mapping does not contain any type variables in the
|
||||||
// parameter list, we don't need to substitute the fields.
|
// parameter list, we don't need to substitute the fields.
|
||||||
// This is also used to prevent infinite substitution...
|
// This is also used to prevent infinite substitution...
|
||||||
let need_subst = params.types().any(|v| {
|
let need_subst = params.values().any(|v| {
|
||||||
let ty = self.unification_table.probe_value(*v);
|
let ty = self.unification_table.probe_value(*v);
|
||||||
if let TypeEnum::TVar { id, .. } = ty.as_ref() {
|
if let TypeEnum::TVar { id, .. } = ty.as_ref() {
|
||||||
mapping.contains_key(id)
|
mapping.contains_key(id)
|
||||||
|
@ -1472,14 +1276,17 @@ impl Unifier {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn subst_map(
|
fn subst_map<K>(
|
||||||
&mut self,
|
&mut self,
|
||||||
map: &VarMap,
|
map: &IndexMapping<K>,
|
||||||
mapping: &SortedVarMap,
|
mapping: &VarMap,
|
||||||
cache: &mut HashMap<Type, Option<Type>>,
|
cache: &mut HashMap<Type, Option<Type>>,
|
||||||
) -> Option<VarMap> {
|
) -> Option<IndexMapping<K>>
|
||||||
|
where
|
||||||
|
K: std::hash::Hash + Eq + Clone,
|
||||||
|
{
|
||||||
let mut map2 = None;
|
let mut map2 = None;
|
||||||
for (k, v) in map.iter() {
|
for (k, v) in map {
|
||||||
if let Some(v1) = self.subst_impl(*v, mapping, cache) {
|
if let Some(v1) = self.subst_impl(*v, mapping, cache) {
|
||||||
if map2.is_none() {
|
if map2.is_none() {
|
||||||
map2 = Some(map.clone());
|
map2 = Some(map.clone());
|
||||||
|
@ -1493,7 +1300,7 @@ impl Unifier {
|
||||||
fn subst_map2<K>(
|
fn subst_map2<K>(
|
||||||
&mut self,
|
&mut self,
|
||||||
map: &Mapping<K, (Type, bool)>,
|
map: &Mapping<K, (Type, bool)>,
|
||||||
mapping: &SortedVarMap,
|
mapping: &VarMap,
|
||||||
cache: &mut HashMap<Type, Option<Type>>,
|
cache: &mut HashMap<Type, Option<Type>>,
|
||||||
) -> Option<Mapping<K, (Type, bool)>>
|
) -> Option<Mapping<K, (Type, bool)>>
|
||||||
where
|
where
|
||||||
|
|
|
@ -45,7 +45,10 @@ impl Unifier {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn map_eq(&mut self, map1: &VarMap, map2: &VarMap) -> bool {
|
fn map_eq<K>(&mut self, map1: &IndexMapping<K>, map2: &IndexMapping<K>) -> bool
|
||||||
|
where
|
||||||
|
K: std::hash::Hash + Eq + Clone
|
||||||
|
{
|
||||||
if map1.len() != map2.len() {
|
if map1.len() != map2.len() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -183,7 +186,7 @@ impl TestEnvironment {
|
||||||
s = &s[1..];
|
s = &s[1..];
|
||||||
ty = self
|
ty = self
|
||||||
.unifier
|
.unifier
|
||||||
.subst(ty, ¶ms.ids().cloned().zip(p.into_iter()).collect())
|
.subst(ty, ¶ms.keys().cloned().zip(p.into_iter()).collect())
|
||||||
.unwrap_or(ty);
|
.unwrap_or(ty);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue