core: Refactor VarMap
There doesn't seem to be a good solution on preserving both the declaration order and sorted variable IDs, so let's just roll a new class that can do both.
parent
6322b6db90
commit
d03ad8a1c4
|
@ -10,7 +10,7 @@ use nac3core::{
|
||||||
},
|
},
|
||||||
typecheck::{
|
typecheck::{
|
||||||
type_inferencer::PrimitiveStore,
|
type_inferencer::PrimitiveStore,
|
||||||
typedef::{Type, TypeEnum, Unifier, VarMap},
|
typedef::{SortedVarMap, Type, TypeEnum, Unifier},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
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::<VarMap>()
|
.collect::<SortedVarMap>()
|
||||||
};
|
};
|
||||||
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::<VarMap>();
|
.collect::<SortedVarMap>();
|
||||||
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: VarMap = params.iter().map(|(id, _)| (*id, ty)).collect();
|
let new_var_map: SortedVarMap = 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::<VarMap>();
|
.collect::<SortedVarMap>();
|
||||||
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 {
|
||||||
|
|
|
@ -50,7 +50,7 @@ pub enum ConcreteTypeEnum {
|
||||||
TObj {
|
TObj {
|
||||||
obj_id: DefinitionId,
|
obj_id: DefinitionId,
|
||||||
fields: HashMap<StrRef, (ConcreteType, bool)>,
|
fields: HashMap<StrRef, (ConcreteType, bool)>,
|
||||||
params: HashMap<u32, ConcreteType>,
|
params: Vec<(u32, ConcreteType)>,
|
||||||
},
|
},
|
||||||
TVirtual {
|
TVirtual {
|
||||||
ty: ConcreteType,
|
ty: ConcreteType,
|
||||||
|
|
|
@ -20,7 +20,7 @@ use crate::{
|
||||||
TopLevelDef,
|
TopLevelDef,
|
||||||
},
|
},
|
||||||
typecheck::{
|
typecheck::{
|
||||||
typedef::{FunSignature, FuncArg, Type, TypeEnum, Unifier, VarMap},
|
typedef::{FunSignature, FuncArg, SortedVarMap, Type, TypeEnum, Unifier},
|
||||||
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: &VarMap,
|
fun_vars: &SortedVarMap,
|
||||||
filter: Option<&Vec<u32>>,
|
filter: Option<&Vec<u32>>,
|
||||||
) -> String {
|
) -> String {
|
||||||
let mut vars = obj
|
let mut vars = obj
|
||||||
|
@ -50,10 +50,10 @@ 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.clone()
|
params.to_sorted()
|
||||||
})
|
})
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
vars.extend(fun_vars.iter());
|
vars.extend(fun_vars);
|
||||||
let sorted = vars.keys().filter(|id| filter.map_or(true, |v| v.contains(id))).sorted();
|
let sorted = vars.keys().filter(|id| filter.map_or(true, |v| v.contains(id))).sorted();
|
||||||
sorted
|
sorted
|
||||||
.map(|id| {
|
.map(|id| {
|
||||||
|
@ -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, filter)
|
get_subst_key(&mut self.unifier, obj, &fun.vars.to_sorted(), 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.keys());
|
filter.extend(params.ids());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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));
|
||||||
|
@ -1977,7 +1977,6 @@ pub fn gen_expr<'ctx, G: CodeGenerator>(
|
||||||
}
|
}
|
||||||
TypeEnum::TObj { obj_id, params, .. } if *obj_id == PRIMITIVE_DEF_IDS.ndarray => {
|
TypeEnum::TObj { obj_id, params, .. } if *obj_id == PRIMITIVE_DEF_IDS.ndarray => {
|
||||||
let (ty, ndims) = params.iter()
|
let (ty, ndims) = params.iter()
|
||||||
.sorted_by_key(|(var_id, _)| *var_id)
|
|
||||||
.map(|(_, ty)| ty)
|
.map(|(_, ty)| ty)
|
||||||
.collect_tuple()
|
.collect_tuple()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
|
@ -10,7 +10,7 @@ use crate::{
|
||||||
},
|
},
|
||||||
typecheck::{
|
typecheck::{
|
||||||
type_inferencer::{FunctionData, Inferencer, PrimitiveStore},
|
type_inferencer::{FunctionData, Inferencer, PrimitiveStore},
|
||||||
typedef::{FunSignature, FuncArg, Type, TypeEnum, Unifier},
|
typedef::{FunSignature, FuncArg, Type, TypeEnum, Unifier, VarMap},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use indoc::indoc;
|
use indoc::indoc;
|
||||||
|
@ -25,7 +25,6 @@ use nac3parser::{
|
||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use crate::typecheck::typedef::VarMap;
|
|
||||||
|
|
||||||
struct Resolver {
|
struct Resolver {
|
||||||
id_to_type: HashMap<StrRef, Type>,
|
id_to_type: HashMap<StrRef, Type>,
|
||||||
|
|
|
@ -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).unwrap_or(*ty);
|
let ty = unifier.subst(*ty, &subst.to_sorted()).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).unwrap_or(*ty);
|
let ty = unifier.subst(*ty, &subst.to_sorted()).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::VarMap,
|
typedef::{SortedVarMap, 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, params);
|
let substituted = unifier.subst(*ty, ¶ms.to_sorted());
|
||||||
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.values().map(|v| match &*unifier.get_ty(*v) {
|
let new_var_ids = vars.types().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.values()).map(|(id, v)| (*id, *v)).collect(),
|
vars: new_var_ids.iter().zip(vars.types()).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);
|
type_vars.extend(vars.to_sorted());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(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
|
||||||
.values()
|
.types()
|
||||||
.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<VarMap> = Vec::default();
|
let mut result: Vec<SortedVarMap> = Vec::default();
|
||||||
for comb in var_combs {
|
for comb in var_combs {
|
||||||
result.push(vars.keys().copied().zip(comb).collect());
|
result.push(vars.ids().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(VarMap::new());
|
result.push(SortedVarMap::new());
|
||||||
}
|
}
|
||||||
(result, no_ranges)
|
(result, no_ranges)
|
||||||
};
|
};
|
||||||
|
@ -1798,7 +1798,7 @@ impl TopLevelComposer {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect::<VarMap>()
|
.collect::<SortedVarMap>()
|
||||||
};
|
};
|
||||||
unifier.subst(self_type, &subst_for_self).unwrap_or(self_type)
|
unifier.subst(self_type, &subst_for_self).unwrap_or(self_type)
|
||||||
})
|
})
|
||||||
|
@ -1926,12 +1926,11 @@ impl TopLevelComposer {
|
||||||
ret_str,
|
ret_str,
|
||||||
name,
|
name,
|
||||||
ast.as_ref().unwrap().location
|
ast.as_ref().unwrap().location
|
||||||
),
|
),]))
|
||||||
]))
|
}
|
||||||
}
|
|
||||||
|
|
||||||
instance_to_stmt.insert(
|
instance_to_stmt.insert(
|
||||||
get_subst_key(unifier, self_type, &subst, Some(&vars.keys().copied().collect())),
|
get_subst_key(unifier, self_type, &subst, Some(&vars.ids().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, VarMap};
|
use super::typecheck::typedef::{FunSignature, FuncArg, SharedUnifier, Type, TypeEnum, Unifier, SortedVarMap};
|
||||||
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: VarMap,
|
pub subst: SortedVarMap,
|
||||||
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, VarMap},
|
typedef::{Type, TypeEnum, Unifier, SortedVarMap},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -28,11 +28,10 @@ pub fn make_ndarray_ty(
|
||||||
|
|
||||||
let tvar_ids = params.iter()
|
let tvar_ids = params.iter()
|
||||||
.map(|(obj_id, _)| *obj_id)
|
.map(|(obj_id, _)| *obj_id)
|
||||||
.sorted()
|
|
||||||
.collect_vec();
|
.collect_vec();
|
||||||
debug_assert_eq!(tvar_ids.len(), 2);
|
debug_assert_eq!(tvar_ids.len(), 2);
|
||||||
|
|
||||||
let mut tvar_subst = VarMap::new();
|
let mut tvar_subst = SortedVarMap::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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ expression: res_vec
|
||||||
"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",
|
"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: [32]\n}\n",
|
"Function {\nname: \"A.__init__\",\nsig: \"fn[[v:V], none]\",\nvar_id: [32]\n}\n",
|
||||||
"Function {\nname: \"A.fun\",\nsig: \"fn[[a:T], V]\",\nvar_id: [37]\n}\n",
|
"Function {\nname: \"A.fun\",\nsig: \"fn[[a:T], V]\",\nvar_id: [37]\n}\n",
|
||||||
"Function {\nname: \"gfun\",\nsig: \"fn[[a:A[int32, list[float]]], none]\",\nvar_id: []\n}\n",
|
"Function {\nname: \"gfun\",\nsig: \"fn[[a:A[list[float], int32]], none]\",\nvar_id: []\n}\n",
|
||||||
"Class {\nname: \"B\",\nancestors: [\"B\"],\nfields: [],\nmethods: [(\"__init__\", \"fn[[], none]\")],\ntype_vars: []\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",
|
"Function {\nname: \"B.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
|
||||||
]
|
]
|
||||||
|
|
|
@ -3,11 +3,11 @@ source: nac3core/src/toplevel/test.rs
|
||||||
expression: res_vec
|
expression: res_vec
|
||||||
---
|
---
|
||||||
[
|
[
|
||||||
"Class {\nname: \"A\",\nancestors: [\"A[typevar18, typevar19]\"],\nfields: [\"a\", \"b\"],\nmethods: [(\"__init__\", \"fn[[a:A[bool, float], b:B], none]\"), (\"fun\", \"fn[[a:A[bool, float]], A[bool, int32]]\")],\ntype_vars: [\"typevar18\", \"typevar19\"]\n}\n",
|
"Class {\nname: \"A\",\nancestors: [\"A[typevar18, typevar19]\"],\nfields: [\"a\", \"b\"],\nmethods: [(\"__init__\", \"fn[[a:A[float, bool], b:B], none]\"), (\"fun\", \"fn[[a:A[float, bool]], A[bool, int32]]\")],\ntype_vars: [\"typevar18\", \"typevar19\"]\n}\n",
|
||||||
"Function {\nname: \"A.__init__\",\nsig: \"fn[[a:A[bool, float], b:B], none]\",\nvar_id: []\n}\n",
|
"Function {\nname: \"A.__init__\",\nsig: \"fn[[a:A[float, bool], b:B], none]\",\nvar_id: []\n}\n",
|
||||||
"Function {\nname: \"A.fun\",\nsig: \"fn[[a:A[bool, float]], A[bool, int32]]\",\nvar_id: []\n}\n",
|
"Function {\nname: \"A.fun\",\nsig: \"fn[[a:A[float, bool]], 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",
|
"Class {\nname: \"B\",\nancestors: [\"B\", \"A[int64, bool]\"],\nfields: [\"a\", \"b\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"fun\", \"fn[[a:A[float, bool]], A[bool, int32]]\"), (\"foo\", \"fn[[b:B], B]\"), (\"bar\", \"fn[[a:A[list[B], int32]], tuple[A[virtual[A[B, int32]], bool], B]]\")],\ntype_vars: []\n}\n",
|
||||||
"Function {\nname: \"B.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
|
"Function {\nname: \"B.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
|
||||||
"Function {\nname: \"B.foo\",\nsig: \"fn[[b:B], B]\",\nvar_id: []\n}\n",
|
"Function {\nname: \"B.foo\",\nsig: \"fn[[b:B], B]\",\nvar_id: []\n}\n",
|
||||||
"Function {\nname: \"B.bar\",\nsig: \"fn[[a:A[int32, list[B]]], tuple[A[bool, virtual[A[B, int32]]], B]]\",\nvar_id: []\n}\n",
|
"Function {\nname: \"B.bar\",\nsig: \"fn[[a:A[list[B], int32]], tuple[A[virtual[A[B, int32]], bool], B]]\",\nvar_id: []\n}\n",
|
||||||
]
|
]
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use crate::symbol_resolver::SymbolValue;
|
use crate::symbol_resolver::SymbolValue;
|
||||||
use crate::toplevel::helper::PRIMITIVE_DEF_IDS;
|
use crate::toplevel::helper::PRIMITIVE_DEF_IDS;
|
||||||
|
use crate::typecheck::typedef::VarMap;
|
||||||
use super::*;
|
use super::*;
|
||||||
use nac3parser::ast::Constant;
|
use nac3parser::ast::Constant;
|
||||||
|
|
||||||
|
@ -482,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).unwrap_or(*ty);
|
let subst_ty = unifier.subst(*ty, &subst.to_sorted()).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).unwrap_or(*ty);
|
let subst_ty = unifier.subst(*ty, &subst.to_sorted()).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, Type, TypeEnum, Unifier, VarMap};
|
use super::typedef::{Call, FunSignature, FuncArg, RecordField, SortedVarMap, 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::<VarMap>();
|
.collect::<SortedVarMap>();
|
||||||
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")
|
||||||
|
|
|
@ -26,13 +26,206 @@ pub struct CallId(pub(super) usize);
|
||||||
|
|
||||||
pub type Mapping<K, V = Type> = HashMap<K, V>;
|
pub type Mapping<K, V = Type> = HashMap<K, V>;
|
||||||
|
|
||||||
/// A [`Mapping`] sorted by its key.
|
/// A sequenced collection storing type variable IDs and their [unifier types][Type], preserving the
|
||||||
///
|
/// order of type variables as it appears in the generic type or function declaration. This type
|
||||||
/// This type is recommended for mappings that should be stored and/or iterated by its sorted key.
|
/// also guarantees the uniqueness of type variable IDs, i.e. only one type variable with the same
|
||||||
pub type SortedMapping<K, V = Type> = BTreeMap<K, V>;
|
/// 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>,
|
||||||
|
}
|
||||||
|
|
||||||
/// A [`BTreeMap`] storing the mapping between type variable ID and [unifier type][`Type`].
|
impl VarMap {
|
||||||
pub type VarMap = SortedMapping<u32>;
|
/// 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 {
|
||||||
|
@ -486,7 +679,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.values().all(|ty| self.is_concrete(*ty, allowed_typevars))
|
vars.types().all(|ty| self.is_concrete(*ty, allowed_typevars))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -920,8 +1113,8 @@ impl Unifier {
|
||||||
// Sort the type arguments by its UnificationKey first, since `HashMap::iter` visits
|
// Sort the type arguments by its UnificationKey first, since `HashMap::iter` visits
|
||||||
// all K-V pairs "in arbitrary order"
|
// all K-V pairs "in arbitrary order"
|
||||||
let (tv1, tv2) = (
|
let (tv1, tv2) = (
|
||||||
params1.iter().sorted_by_key(|(k, _)| *k).map(|(_, v)| v).collect_vec(),
|
params1.iter().map(|(_, v)| v).collect_vec(),
|
||||||
params2.iter().sorted_by_key(|(k, _)| *k).map(|(_, v)| v).collect_vec(),
|
params2.iter().map(|(_, v)| v).collect_vec(),
|
||||||
);
|
);
|
||||||
for (x, y) in zip(tv1, tv2) {
|
for (x, y) in zip(tv1, tv2) {
|
||||||
if self.unify_impl(*x, *y, false).is_err() {
|
if self.unify_impl(*x, *y, false).is_err() {
|
||||||
|
@ -1097,11 +1290,9 @@ impl Unifier {
|
||||||
if params.is_empty() {
|
if params.is_empty() {
|
||||||
name
|
name
|
||||||
} else {
|
} else {
|
||||||
let params = params
|
let mut params = params
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(_, v)| self.internal_stringify(*v, obj_to_name, var_to_name, notes));
|
.map(|(_, v)| self.internal_stringify(*v, obj_to_name, var_to_name, notes));
|
||||||
// sort to preserve order
|
|
||||||
let mut params = params.sorted();
|
|
||||||
format!("{}[{}]", name, params.join(", "))
|
format!("{}[{}]", name, params.join(", "))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1151,7 +1342,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 {
|
for (k, v) in fun.vars.iter() {
|
||||||
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()
|
||||||
{
|
{
|
||||||
|
@ -1181,14 +1372,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: &VarMap) -> Option<Type> {
|
pub fn subst(&mut self, a: Type, mapping: &SortedVarMap) -> 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: &VarMap,
|
mapping: &SortedVarMap,
|
||||||
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);
|
||||||
|
@ -1231,7 +1422,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.values().any(|v| {
|
let need_subst = params.types().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)
|
||||||
|
@ -1281,17 +1472,14 @@ impl Unifier {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn subst_map<K>(
|
fn subst_map(
|
||||||
&mut self,
|
&mut self,
|
||||||
map: &SortedMapping<K>,
|
map: &VarMap,
|
||||||
mapping: &VarMap,
|
mapping: &SortedVarMap,
|
||||||
cache: &mut HashMap<Type, Option<Type>>,
|
cache: &mut HashMap<Type, Option<Type>>,
|
||||||
) -> Option<SortedMapping<K>>
|
) -> Option<VarMap> {
|
||||||
where
|
|
||||||
K: Ord + Eq + Clone,
|
|
||||||
{
|
|
||||||
let mut map2 = None;
|
let mut map2 = None;
|
||||||
for (k, v) in map {
|
for (k, v) in map.iter() {
|
||||||
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());
|
||||||
|
@ -1305,7 +1493,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: &VarMap,
|
mapping: &SortedVarMap,
|
||||||
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,10 +45,7 @@ impl Unifier {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn map_eq<K>(&mut self, map1: &SortedMapping<K>, map2: &SortedMapping<K>) -> bool
|
fn map_eq(&mut self, map1: &VarMap, map2: &VarMap) -> bool {
|
||||||
where
|
|
||||||
K: Ord + Eq + Clone,
|
|
||||||
{
|
|
||||||
if map1.len() != map2.len() {
|
if map1.len() != map2.len() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -186,7 +183,7 @@ impl TestEnvironment {
|
||||||
s = &s[1..];
|
s = &s[1..];
|
||||||
ty = self
|
ty = self
|
||||||
.unifier
|
.unifier
|
||||||
.subst(ty, ¶ms.keys().cloned().zip(p.into_iter()).collect())
|
.subst(ty, ¶ms.ids().cloned().zip(p.into_iter()).collect())
|
||||||
.unwrap_or(ty);
|
.unwrap_or(ty);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue