1
0
forked from M-Labs/nac3

core: refactor to use TypeVarId and TypeVar

This commit is contained in:
lyken 2024-06-13 13:28:39 +08:00
parent dc874f2994
commit f026b48e2a
19 changed files with 309 additions and 302 deletions

View File

@ -9,7 +9,7 @@ use nac3core::{
},
typecheck::{
type_inferencer::PrimitiveStore,
typedef::{Type, TypeEnum, Unifier, VarMap},
typedef::{iter_type_vars, to_var_map, Type, TypeEnum, TypeVar, Unifier, VarMap},
},
};
use nac3parser::ast::{self, StrRef};
@ -317,13 +317,13 @@ impl InnerResolver {
Ok(Ok((primitives.exception, true)))
} else if ty_id == self.primitive_ids.list {
// do not handle type var param and concrete check here
let var = unifier.get_dummy_var().0;
let var = unifier.get_dummy_var().ty;
let list = unifier.add_ty(TypeEnum::TList { ty: var });
Ok(Ok((list, false)))
} else if ty_id == self.primitive_ids.ndarray {
// do not handle type var param and concrete check here
let var = unifier.get_dummy_var().0;
let ndims = unifier.get_fresh_const_generic_var(primitives.usize(), None, None).0;
let var = unifier.get_dummy_var().ty;
let ndims = unifier.get_fresh_const_generic_var(primitives.usize(), None, None).ty;
let ndarray = make_ndarray_ty(unifier, primitives, Some(var), Some(ndims));
Ok(Ok((ndarray, false)))
} else if ty_id == self.primitive_ids.tuple {
@ -383,7 +383,7 @@ impl InnerResolver {
}
if !is_const_generic && needs_defer {
result.push(unifier.get_dummy_var().0);
result.push(unifier.get_dummy_var().ty);
} else {
result.push({
match self.get_pyty_obj_type(py, constr, unifier, defs, primitives)? {
@ -426,9 +426,9 @@ impl InnerResolver {
)));
}
unifier.get_fresh_const_generic_var(constraint_types[0], Some(name.into()), None).0
unifier.get_fresh_const_generic_var(constraint_types[0], Some(name.into()), None).ty
} else {
unifier.get_fresh_var_with_range(&constraint_types, Some(name.into()), None).0
unifier.get_fresh_var_with_range(&constraint_types, Some(name.into()), None).ty
};
Ok(Ok((res, true)))
@ -568,7 +568,7 @@ impl InnerResolver {
} else if ty_id == self.primitive_ids.virtual_id {
Ok(Ok((
{
let ty = TypeEnum::TVirtual { ty: unifier.get_dummy_var().0 };
let ty = TypeEnum::TVirtual { ty: unifier.get_dummy_var().ty };
unifier.add_ty(ty)
},
false,
@ -719,18 +719,16 @@ impl InnerResolver {
unreachable!("must be tobj")
};
let var_map = params
.iter()
.map(|(id_var, ty)| {
let TypeEnum::TVar { id, range, name, loc, .. } = &*unifier.get_ty(*ty)
let var_map = to_var_map(iter_type_vars(params).map(|tvar| {
let TypeEnum::TVar { id, range, name, loc, .. } = &*unifier.get_ty(tvar.ty)
else {
unreachable!()
};
assert_eq!(*id, *id_var);
(*id, unifier.get_fresh_var_with_range(range, *name, *loc).0)
})
.collect::<VarMap>();
assert_eq!(*id, tvar.id);
let ty = unifier.get_fresh_var_with_range(range, *name, *loc).ty;
TypeVar { id: *id, ty }
}));
return Ok(Ok(unifier.subst(primitives.option, &var_map).unwrap()));
}
@ -748,18 +746,16 @@ impl InnerResolver {
}
(TypeEnum::TObj { params, fields, .. }, false) => {
self.pyid_to_type.write().insert(py_obj_id, extracted_ty);
let var_map = params
.iter()
.map(|(id_var, ty)| {
let TypeEnum::TVar { id, range, name, loc, .. } = &*unifier.get_ty(*ty)
let var_map = to_var_map(iter_type_vars(params).map(|tvar| {
let TypeEnum::TVar { id, range, name, loc, .. } = &*unifier.get_ty(tvar.ty)
else {
unreachable!()
};
assert_eq!(*id, *id_var);
(*id, unifier.get_fresh_var_with_range(range, *name, *loc).0)
})
.collect::<VarMap>();
assert_eq!(*id, tvar.id);
let ty = unifier.get_fresh_var_with_range(range, *name, *loc).ty;
TypeVar { id: *id, ty }
}));
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, VarMap},
typedef::{to_var_map, FunSignature, FuncArg, Type, TypeEnum, TypeVar, TypeVarId, Unifier},
},
};
@ -51,7 +51,7 @@ pub enum ConcreteTypeEnum {
TObj {
obj_id: DefinitionId,
fields: HashMap<StrRef, (ConcreteType, bool)>,
params: IndexMap<u32, ConcreteType>,
params: IndexMap<TypeVarId, ConcreteType>,
},
TVirtual {
ty: ConcreteType,
@ -59,7 +59,7 @@ pub enum ConcreteTypeEnum {
TFunc {
args: Vec<ConcreteFuncArg>,
ret: ConcreteType,
vars: HashMap<u32, ConcreteType>,
vars: HashMap<TypeVarId, ConcreteType>,
},
TLiteral {
values: Vec<SymbolValue>,
@ -230,7 +230,7 @@ impl ConcreteTypeStore {
return if let Some(ty) = ty {
*ty
} else {
*ty = Some(unifier.get_dummy_var().0);
*ty = Some(unifier.get_dummy_var().ty);
ty.unwrap()
};
}
@ -272,10 +272,10 @@ impl ConcreteTypeStore {
(*name, (self.to_unifier_type(unifier, primitives, cty.0, cache), cty.1))
})
.collect::<HashMap<_, _>>(),
params: params
.iter()
.map(|(id, cty)| (*id, self.to_unifier_type(unifier, primitives, *cty, cache)))
.collect::<VarMap>(),
params: to_var_map(params.iter().map(|(&id, cty)| {
let ty = self.to_unifier_type(unifier, primitives, *cty, cache);
TypeVar { id, ty }
})),
},
ConcreteTypeEnum::TFunc { args, ret, vars } => TypeEnum::TFunc(FunSignature {
args: args
@ -287,10 +287,10 @@ impl ConcreteTypeStore {
})
.collect(),
ret: self.to_unifier_type(unifier, primitives, *ret, cache),
vars: vars
.iter()
.map(|(id, cty)| (*id, self.to_unifier_type(unifier, primitives, *cty, cache)))
.collect::<VarMap>(),
vars: to_var_map(vars.iter().map(|(&id, cty)| {
let ty = self.to_unifier_type(unifier, primitives, *cty, cache);
TypeVar { id, ty }
})),
}),
ConcreteTypeEnum::TLiteral { values, .. } => {
TypeEnum::TLiteral { values: values.clone(), loc: None }

View File

@ -22,7 +22,7 @@ use crate::{
},
typecheck::{
magic_methods::{binop_assign_name, binop_name, unaryop_name},
typedef::{FunSignature, FuncArg, Type, TypeEnum, Unifier, VarMap},
typedef::{FunSignature, FuncArg, Type, TypeEnum, TypeVarId, Unifier, VarMap},
},
};
use inkwell::{
@ -42,7 +42,7 @@ pub fn get_subst_key(
unifier: &mut Unifier,
obj: Option<Type>,
fun_vars: &VarMap,
filter: Option<&Vec<u32>>,
filter: Option<&Vec<TypeVarId>>,
) -> String {
let mut vars = obj
.map(|ty| {
@ -81,7 +81,7 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> {
&mut self,
obj: Option<Type>,
fun: &FunSignature,
filter: Option<&Vec<u32>>,
filter: Option<&Vec<TypeVarId>>,
) -> String {
get_subst_key(&mut self.unifier, obj, &fun.vars, filter)
}

View File

@ -25,7 +25,7 @@ use crate::{
},
symbol_resolver::SymbolValue,
toplevel::{helper::PrimDef, numpy::make_ndarray_ty},
typecheck::typedef::VarMap,
typecheck::typedef::{iter_type_vars, to_var_map, TypeVar, VarMap},
};
use super::*;
@ -307,26 +307,26 @@ struct BuiltinBuilder<'a> {
is_some_ty: (Type, bool),
unwrap_ty: (Type, bool),
option_tvar: (Type, u32),
option_tvar: TypeVar,
ndarray_dtype_tvar: (Type, u32),
ndarray_ndims_tvar: (Type, u32),
ndarray_dtype_tvar: TypeVar,
ndarray_ndims_tvar: TypeVar,
ndarray_copy_ty: (Type, bool),
ndarray_fill_ty: (Type, bool),
list_int32: Type,
num_ty: (Type, u32),
num_ty: TypeVar,
num_var_map: VarMap,
ndarray_float: Type,
ndarray_float_2d: Type,
ndarray_num_ty: Type,
float_or_ndarray_ty: (Type, u32),
float_or_ndarray_ty: TypeVar,
float_or_ndarray_var_map: VarMap,
num_or_ndarray_ty: (Type, u32),
num_or_ndarray_ty: TypeVar,
num_or_ndarray_var_map: VarMap,
}
@ -350,7 +350,7 @@ impl<'a> BuiltinBuilder<'a> {
(
*fields.get(&PrimDef::OptionIsSome.simple_name().into()).unwrap(),
*fields.get(&PrimDef::OptionUnwrap.simple_name().into()).unwrap(),
(*params.iter().next().unwrap().1, *params.iter().next().unwrap().0),
iter_type_vars(params).next().unwrap(),
)
} else {
unreachable!()
@ -361,10 +361,8 @@ impl<'a> BuiltinBuilder<'a> {
else {
unreachable!()
};
let ndarray_dtype_tvar =
ndarray_params.iter().next().map(|(var_id, ty)| (*ty, *var_id)).unwrap();
let ndarray_ndims_tvar =
ndarray_params.iter().nth(1).map(|(var_id, ty)| (*ty, *var_id)).unwrap();
let ndarray_dtype_tvar = iter_type_vars(ndarray_params).next().unwrap();
let ndarray_ndims_tvar = iter_type_vars(ndarray_params).nth(1).unwrap();
let ndarray_copy_ty =
*ndarray_fields.get(&PrimDef::NDArrayCopy.simple_name().into()).unwrap();
let ndarray_fill_ty =
@ -375,7 +373,7 @@ impl<'a> BuiltinBuilder<'a> {
Some("N".into()),
None,
);
let num_var_map: VarMap = vec![(num_ty.1, num_ty.0)].into_iter().collect();
let num_var_map = to_var_map([num_ty]);
let ndarray_float = make_ndarray_ty(unifier, primitives, Some(float), None);
let ndarray_float_2d = {
@ -389,18 +387,14 @@ impl<'a> BuiltinBuilder<'a> {
make_ndarray_ty(unifier, primitives, Some(float), Some(ndims))
};
let ndarray_num_ty = make_ndarray_ty(unifier, primitives, Some(num_ty.0), None);
let ndarray_num_ty = make_ndarray_ty(unifier, primitives, Some(num_ty.ty), None);
let float_or_ndarray_ty =
unifier.get_fresh_var_with_range(&[float, ndarray_float], Some("T".into()), None);
let float_or_ndarray_var_map: VarMap =
vec![(float_or_ndarray_ty.1, float_or_ndarray_ty.0)].into_iter().collect();
let float_or_ndarray_var_map = to_var_map([float_or_ndarray_ty]);
let num_or_ndarray_ty =
unifier.get_fresh_var_with_range(&[num_ty.0, ndarray_num_ty], Some("T".into()), None);
let num_or_ndarray_var_map: VarMap =
vec![(num_ty.1, num_ty.0), (num_or_ndarray_ty.1, num_or_ndarray_ty.0)]
.into_iter()
.collect();
unifier.get_fresh_var_with_range(&[num_ty.ty, ndarray_num_ty], Some("T".into()), None);
let num_or_ndarray_var_map = to_var_map([num_ty, num_or_ndarray_ty]);
let list_int32 = unifier.add_ty(TypeEnum::TList { ty: int32 });
@ -648,7 +642,7 @@ impl<'a> BuiltinBuilder<'a> {
PrimDef::Option => TopLevelDef::Class {
name: prim.name().into(),
object_id: prim.id(),
type_vars: vec![self.option_tvar.0],
type_vars: vec![self.option_tvar.ty],
fields: vec![],
methods: vec![
Self::create_method(PrimDef::OptionIsSome, self.is_some_ty.0),
@ -668,7 +662,7 @@ impl<'a> BuiltinBuilder<'a> {
name: prim.name().into(),
simple_name: prim.simple_name().into(),
signature: self.unwrap_ty.0,
var_id: vec![self.option_tvar.1],
var_id: vec![self.option_tvar.id],
instance_to_symbol: HashMap::default(),
instance_to_stmt: HashMap::default(),
resolver: None,
@ -682,7 +676,7 @@ impl<'a> BuiltinBuilder<'a> {
name: prim.name().to_string(),
simple_name: prim.simple_name().into(),
signature: self.is_some_ty.0,
var_id: vec![self.option_tvar.1],
var_id: vec![self.option_tvar.id],
instance_to_symbol: HashMap::default(),
instance_to_stmt: HashMap::default(),
resolver: None,
@ -719,13 +713,13 @@ impl<'a> BuiltinBuilder<'a> {
signature: self.unifier.add_ty(TypeEnum::TFunc(FunSignature {
args: vec![FuncArg {
name: "n".into(),
ty: self.option_tvar.0,
ty: self.option_tvar.ty,
default_value: None,
}],
ret: self.primitives.option,
vars: VarMap::from([(self.option_tvar.1, self.option_tvar.0)]),
vars: to_var_map([self.option_tvar]),
})),
var_id: vec![self.option_tvar.1],
var_id: vec![self.option_tvar.id],
instance_to_symbol: HashMap::default(),
instance_to_stmt: HashMap::default(),
resolver: None,
@ -761,7 +755,7 @@ impl<'a> BuiltinBuilder<'a> {
PrimDef::NDArray => TopLevelDef::Class {
name: prim.name().into(),
object_id: prim.id(),
type_vars: vec![self.ndarray_dtype_tvar.0, self.ndarray_ndims_tvar.0],
type_vars: vec![self.ndarray_dtype_tvar.ty, self.ndarray_ndims_tvar.ty],
fields: Vec::default(),
methods: vec![
Self::create_method(PrimDef::NDArrayCopy, self.ndarray_copy_ty.0),
@ -777,7 +771,7 @@ impl<'a> BuiltinBuilder<'a> {
name: prim.name().into(),
simple_name: prim.simple_name().into(),
signature: self.ndarray_copy_ty.0,
var_id: vec![self.ndarray_dtype_tvar.1, self.ndarray_ndims_tvar.1],
var_id: vec![self.ndarray_dtype_tvar.id, self.ndarray_ndims_tvar.id],
instance_to_symbol: HashMap::default(),
instance_to_stmt: HashMap::default(),
resolver: None,
@ -794,7 +788,7 @@ impl<'a> BuiltinBuilder<'a> {
name: prim.name().into(),
simple_name: prim.simple_name().into(),
signature: self.ndarray_fill_ty.0,
var_id: vec![self.ndarray_dtype_tvar.1, self.ndarray_ndims_tvar.1],
var_id: vec![self.ndarray_dtype_tvar.id, self.ndarray_ndims_tvar.id],
instance_to_symbol: HashMap::default(),
instance_to_stmt: HashMap::default(),
resolver: None,
@ -831,10 +825,10 @@ impl<'a> BuiltinBuilder<'a> {
signature: self.unifier.add_ty(TypeEnum::TFunc(FunSignature {
args: vec![FuncArg {
name: "n".into(),
ty: self.num_or_ndarray_ty.0,
ty: self.num_or_ndarray_ty.ty,
default_value: None,
}],
ret: self.num_or_ndarray_ty.0,
ret: self.num_or_ndarray_ty.ty,
vars: self.num_or_ndarray_var_map.clone(),
})),
var_id: Vec::default(),
@ -884,9 +878,9 @@ impl<'a> BuiltinBuilder<'a> {
let int_sized = size_variant.of_int(self.primitives);
let ndarray_int_sized =
make_ndarray_ty(self.unifier, self.primitives, Some(int_sized), Some(common_ndim.0));
make_ndarray_ty(self.unifier, self.primitives, Some(int_sized), Some(common_ndim.ty));
let ndarray_float =
make_ndarray_ty(self.unifier, self.primitives, Some(float), Some(common_ndim.0));
make_ndarray_ty(self.unifier, self.primitives, Some(float), Some(common_ndim.ty));
let p0_ty =
self.unifier.get_fresh_var_with_range(&[float, ndarray_float], Some("T".into()), None);
@ -898,12 +892,10 @@ impl<'a> BuiltinBuilder<'a> {
create_fn_by_codegen(
self.unifier,
&[(common_ndim.1, common_ndim.0), (p0_ty.1, p0_ty.0), (ret_ty.1, ret_ty.0)]
.into_iter()
.collect(),
&to_var_map([common_ndim, p0_ty, ret_ty]),
prim.name(),
ret_ty.0,
&[(p0_ty.0, "n")],
ret_ty.ty,
&[(p0_ty.ty, "n")],
Box::new(move |ctx, _, fun, args, generator| {
let arg_ty = fun.0.args[0].ty;
let arg = args[0].1.clone().to_basic_value_enum(ctx, generator, arg_ty)?;
@ -946,12 +938,12 @@ impl<'a> BuiltinBuilder<'a> {
);
let ndarray_float =
make_ndarray_ty(self.unifier, self.primitives, Some(float), Some(common_ndim.0));
make_ndarray_ty(self.unifier, self.primitives, Some(float), Some(common_ndim.ty));
// The size variant of the function determines the type of int returned
let int_sized = size_variant.of_int(self.primitives);
let ndarray_int_sized =
make_ndarray_ty(self.unifier, self.primitives, Some(int_sized), Some(common_ndim.0));
make_ndarray_ty(self.unifier, self.primitives, Some(int_sized), Some(common_ndim.ty));
let p0_ty =
self.unifier.get_fresh_var_with_range(&[float, ndarray_float], Some("T".into()), None);
@ -964,12 +956,10 @@ impl<'a> BuiltinBuilder<'a> {
create_fn_by_codegen(
self.unifier,
&[(common_ndim.1, common_ndim.0), (p0_ty.1, p0_ty.0), (ret_ty.1, ret_ty.0)]
.into_iter()
.collect(),
&to_var_map([common_ndim, p0_ty, ret_ty]),
prim.name(),
ret_ty.0,
&[(p0_ty.0, "n")],
ret_ty.ty,
&[(p0_ty.ty, "n")],
Box::new(move |ctx, _, fun, args, generator| {
let arg_ty = fun.0.args[0].ty;
let arg = args[0].1.clone().to_basic_value_enum(ctx, generator, arg_ty)?;
@ -1031,7 +1021,7 @@ impl<'a> BuiltinBuilder<'a> {
simple_name: prim.simple_name().into(),
signature: self.unifier.add_ty(TypeEnum::TFunc(FunSignature {
args: vec![
FuncArg { name: "object".into(), ty: tv.0, default_value: None },
FuncArg { name: "object".into(), ty: tv.ty, default_value: None },
FuncArg {
name: "copy".into(),
ty: bool,
@ -1044,9 +1034,9 @@ impl<'a> BuiltinBuilder<'a> {
},
],
ret: ndarray,
vars: VarMap::from([(tv.1, tv.0)]),
vars: to_var_map([tv]),
})),
var_id: vec![tv.1],
var_id: vec![tv.id],
instance_to_symbol: HashMap::default(),
instance_to_stmt: HashMap::default(),
resolver: None,
@ -1064,12 +1054,12 @@ impl<'a> BuiltinBuilder<'a> {
create_fn_by_codegen(
self.unifier,
&[(tv.1, tv.0)].into_iter().collect(),
&to_var_map([tv]),
prim.name(),
self.primitives.ndarray,
// We are using List[int32] here, as I don't know a way to specify an n-tuple bound on a
// type variable
&[(self.list_int32, "shape"), (tv.0, "fill_value")],
&[(self.list_int32, "shape"), (tv.ty, "fill_value")],
Box::new(move |ctx, obj, fun, args, generator| {
gen_ndarray_full(ctx, &obj, fun, &args, generator)
.map(|val| Some(val.as_basic_value_enum()))
@ -1287,8 +1277,8 @@ impl<'a> BuiltinBuilder<'a> {
self.unifier,
&self.float_or_ndarray_var_map,
prim.name(),
self.float_or_ndarray_ty.0,
&[(self.float_or_ndarray_ty.0, "n")],
self.float_or_ndarray_ty.ty,
&[(self.float_or_ndarray_ty.ty, "n")],
Box::new(move |ctx, _, fun, args, generator| {
let arg_ty = fun.0.args[0].ty;
let arg = args[0].1.clone().to_basic_value_enum(ctx, generator, arg_ty)?;
@ -1311,8 +1301,8 @@ impl<'a> BuiltinBuilder<'a> {
self.unifier,
&self.float_or_ndarray_var_map,
prim.name(),
self.float_or_ndarray_ty.0,
&[(self.float_or_ndarray_ty.0, "n")],
self.float_or_ndarray_ty.ty,
&[(self.float_or_ndarray_ty.ty, "n")],
Box::new(|ctx, _, fun, args, generator| {
let arg_ty = fun.0.args[0].ty;
let arg = args[0].1.clone().to_basic_value_enum(ctx, generator, arg_ty)?;
@ -1328,9 +1318,9 @@ impl<'a> BuiltinBuilder<'a> {
let PrimitiveStore { uint64, int32, .. } = *self.primitives;
let tvar = self.unifier.get_fresh_var(Some("L".into()), None);
let list = self.unifier.add_ty(TypeEnum::TList { ty: tvar.0 });
let list = self.unifier.add_ty(TypeEnum::TList { ty: tvar.ty });
let ndims = self.unifier.get_fresh_const_generic_var(uint64, Some("N".into()), None);
let ndarray = make_ndarray_ty(self.unifier, self.primitives, Some(tvar.0), Some(ndims.0));
let ndarray = make_ndarray_ty(self.unifier, self.primitives, Some(tvar.ty), Some(ndims.ty));
let arg_ty = self.unifier.get_fresh_var_with_range(
&[list, ndarray, self.primitives.range],
@ -1341,9 +1331,9 @@ impl<'a> BuiltinBuilder<'a> {
name: prim.name().into(),
simple_name: prim.simple_name().into(),
signature: self.unifier.add_ty(TypeEnum::TFunc(FunSignature {
args: vec![FuncArg { name: "ls".into(), ty: arg_ty.0, default_value: None }],
args: vec![FuncArg { name: "ls".into(), ty: arg_ty.ty, default_value: None }],
ret: int32,
vars: vec![(tvar.1, tvar.0), (arg_ty.1, arg_ty.0)].into_iter().collect(),
vars: to_var_map([tvar, arg_ty]),
})),
var_id: Vec::default(),
instance_to_symbol: HashMap::default(),
@ -1446,10 +1436,10 @@ impl<'a> BuiltinBuilder<'a> {
simple_name: prim.simple_name().into(),
signature: self.unifier.add_ty(TypeEnum::TFunc(FunSignature {
args: vec![
FuncArg { name: "m".into(), ty: self.num_ty.0, default_value: None },
FuncArg { name: "n".into(), ty: self.num_ty.0, default_value: None },
FuncArg { name: "m".into(), ty: self.num_ty.ty, default_value: None },
FuncArg { name: "n".into(), ty: self.num_ty.ty, default_value: None },
],
ret: self.num_ty.0,
ret: self.num_ty.ty,
vars: self.num_var_map.clone(),
})),
var_id: Vec::default(),
@ -1484,15 +1474,15 @@ impl<'a> BuiltinBuilder<'a> {
.num_or_ndarray_var_map
.clone()
.into_iter()
.chain(once((ret_ty.1, ret_ty.0)))
.chain(once((ret_ty.id, ret_ty.ty)))
.collect::<IndexMap<_, _>>();
create_fn_by_codegen(
self.unifier,
&var_map,
prim.name(),
ret_ty.0,
&[(self.float_or_ndarray_ty.0, "a")],
ret_ty.ty,
&[(self.float_or_ndarray_ty.ty, "a")],
Box::new(move |ctx, _, fun, args, generator| {
let a_ty = fun.0.args[0].ty;
let a = args[0].1.clone().to_basic_value_enum(ctx, generator, a_ty)?;
@ -1512,9 +1502,9 @@ impl<'a> BuiltinBuilder<'a> {
fn build_np_minimum_maximum_function(&mut self, prim: PrimDef) -> TopLevelDef {
debug_assert_prim_is_allowed(prim, &[PrimDef::FunNpMinimum, PrimDef::FunNpMaximum]);
let x1_ty = self.new_type_or_ndarray_ty(self.num_ty.0);
let x2_ty = self.new_type_or_ndarray_ty(self.num_ty.0);
let param_ty = &[(x1_ty.0, "x1"), (x2_ty.0, "x2")];
let x1_ty = self.new_type_or_ndarray_ty(self.num_ty.ty);
let x2_ty = self.new_type_or_ndarray_ty(self.num_ty.ty);
let param_ty = &[(x1_ty.ty, "x1"), (x2_ty.ty, "x2")];
let ret_ty = self.unifier.get_fresh_var(None, None);
TopLevelDef::Function {
@ -1525,12 +1515,10 @@ impl<'a> BuiltinBuilder<'a> {
.iter()
.map(|p| FuncArg { name: p.1.into(), ty: p.0, default_value: None })
.collect(),
ret: ret_ty.0,
vars: [(x1_ty.1, x1_ty.0), (x2_ty.1, x2_ty.0), (ret_ty.1, ret_ty.0)]
.into_iter()
.collect(),
ret: ret_ty.ty,
vars: to_var_map([x1_ty, x2_ty, ret_ty]),
})),
var_id: vec![x1_ty.1, x2_ty.1],
var_id: vec![x1_ty.id, x2_ty.id],
instance_to_symbol: HashMap::default(),
instance_to_stmt: HashMap::default(),
resolver: None,
@ -1564,10 +1552,10 @@ impl<'a> BuiltinBuilder<'a> {
signature: self.unifier.add_ty(TypeEnum::TFunc(FunSignature {
args: vec![FuncArg {
name: "n".into(),
ty: self.num_or_ndarray_ty.0,
ty: self.num_or_ndarray_ty.ty,
default_value: None,
}],
ret: self.num_or_ndarray_ty.0,
ret: self.num_or_ndarray_ty.ty,
vars: self.num_or_ndarray_var_map.clone(),
})),
var_id: Vec::default(),
@ -1660,8 +1648,8 @@ impl<'a> BuiltinBuilder<'a> {
self.unifier,
&self.float_or_ndarray_var_map,
prim.name(),
self.float_or_ndarray_ty.0,
&[(self.float_or_ndarray_ty.0, arg_name)],
self.float_or_ndarray_ty.ty,
&[(self.float_or_ndarray_ty.ty, arg_name)],
Box::new(move |ctx, _, fun, args, generator| {
let arg_ty = fun.0.args[0].ty;
let arg_val = args[0].1.clone().to_basic_value_enum(ctx, generator, arg_ty)?;
@ -1745,7 +1733,7 @@ impl<'a> BuiltinBuilder<'a> {
let x1_ty = self.new_type_or_ndarray_ty(x1_ty);
let x2_ty = self.new_type_or_ndarray_ty(x2_ty);
let param_ty = &[(x1_ty.0, "x1"), (x2_ty.0, "x2")];
let param_ty = &[(x1_ty.ty, "x1"), (x2_ty.ty, "x2")];
let ret_ty = self.unifier.get_fresh_var(None, None);
TopLevelDef::Function {
@ -1756,12 +1744,10 @@ impl<'a> BuiltinBuilder<'a> {
.iter()
.map(|p| FuncArg { name: p.1.into(), ty: p.0, default_value: None })
.collect(),
ret: ret_ty.0,
vars: [(x1_ty.1, x1_ty.0), (x2_ty.1, x2_ty.0), (ret_ty.1, ret_ty.0)]
.into_iter()
.collect(),
ret: ret_ty.ty,
vars: to_var_map([x1_ty, x2_ty, ret_ty]),
})),
var_id: vec![ret_ty.1],
var_id: vec![ret_ty.id],
instance_to_symbol: HashMap::default(),
instance_to_stmt: HashMap::default(),
resolver: None,
@ -1794,7 +1780,7 @@ impl<'a> BuiltinBuilder<'a> {
(prim.simple_name().into(), method_ty, prim.id())
}
fn new_type_or_ndarray_ty(&mut self, scalar_ty: Type) -> (Type, u32) {
fn new_type_or_ndarray_ty(&mut self, scalar_ty: Type) -> TypeVar {
let ndarray = make_ndarray_ty(self.unifier, self.primitives, Some(scalar_ty), None);
self.unifier.get_fresh_var_with_range(&[scalar_ty, ndarray], Some("T".into()), None)

View File

@ -6,7 +6,7 @@ use crate::{
symbol_resolver::SymbolValue,
typecheck::{
type_inferencer::{FunctionData, Inferencer},
typedef::VarMap,
typedef::{TypeVar, VarMap},
},
};
@ -225,7 +225,7 @@ impl TopLevelComposer {
// since later when registering class method, ast will still be used,
// here push None temporarily, later will move the ast inside
let constructor_ty = self.unifier.get_dummy_var().0;
let constructor_ty = self.unifier.get_dummy_var().ty;
let mut class_def_ast = (
Arc::new(RwLock::new(Self::make_top_level_class_def(
DefinitionId(class_def_id),
@ -281,7 +281,7 @@ impl TopLevelComposer {
};
// dummy method define here
let dummy_method_type = self.unifier.get_dummy_var().0;
let dummy_method_type = self.unifier.get_dummy_var().ty;
class_method_name_def_ids.push((
*method_name,
RwLock::new(Self::make_top_level_function_def(
@ -337,7 +337,7 @@ impl TopLevelComposer {
}
let fun_name = *name;
let ty_to_be_unified = self.unifier.get_dummy_var().0;
let ty_to_be_unified = self.unifier.get_dummy_var().ty;
// add to the definition list
self.definition_ast_list.push((
RwLock::new(Self::make_top_level_function_def(
@ -452,7 +452,7 @@ impl TopLevelComposer {
// check if all are unique type vars
let all_unique_type_var = {
let mut occurred_type_var_id: HashSet<u32> = HashSet::new();
let mut occurred_type_var_id: HashSet<TypeVarId> = HashSet::new();
type_vars.iter().all(|x| {
let ty = unifier.get_ty(*x);
if let TypeEnum::TVar { id, .. } = ty.as_ref() {
@ -917,18 +917,19 @@ impl TopLevelComposer {
let type_vars_within =
get_type_var_contained_in_type_annotation(&type_annotation)
.into_iter()
.map(|x| -> Result<(u32, Type), HashSet<String>> {
.map(|x| -> Result<TypeVar, HashSet<String>> {
let TypeAnnotation::TypeVar(ty) = x else {
unreachable!("must be type var annotation kind")
};
Ok((Self::get_var_id(ty, unifier)?, ty))
let id = Self::get_var_id(ty, unifier)?;
Ok(TypeVar { id, ty })
})
.collect::<Result<Vec<_>, _>>()?;
for (id, ty) in type_vars_within {
if let Some(prev_ty) = function_var_map.insert(id, ty) {
for var in type_vars_within {
if let Some(prev_ty) = function_var_map.insert(var.id, var.ty) {
// if already have the type inserted, make sure they are the same thing
assert_eq!(prev_ty, ty);
assert_eq!(prev_ty, var.ty);
}
}
@ -982,18 +983,19 @@ impl TopLevelComposer {
let type_vars_within =
get_type_var_contained_in_type_annotation(&return_ty_annotation)
.into_iter()
.map(|x| -> Result<(u32, Type), HashSet<String>> {
.map(|x| -> Result<TypeVar, HashSet<String>> {
let TypeAnnotation::TypeVar(ty) = x else {
unreachable!("must be type var here")
};
Ok((Self::get_var_id(ty, unifier)?, ty))
let id = Self::get_var_id(ty, unifier)?;
Ok(TypeVar { id, ty })
})
.collect::<Result<Vec<_>, _>>()?;
for (id, ty) in type_vars_within {
if let Some(prev_ty) = function_var_map.insert(id, ty) {
for var in type_vars_within {
if let Some(prev_ty) = function_var_map.insert(var.id, var.ty) {
// if already have the type inserted, make sure they are the same thing
assert_eq!(prev_ty, ty);
assert_eq!(prev_ty, var.ty);
}
}
@ -1177,7 +1179,7 @@ impl TopLevelComposer {
// finish handling type vars
let dummy_func_arg = FuncArg {
name,
ty: unifier.get_dummy_var().0,
ty: unifier.get_dummy_var().ty,
default_value: match default {
None => None,
Some(default) => {
@ -1240,13 +1242,13 @@ impl TopLevelComposer {
assert_eq!(prev_ty, ty);
}
}
let dummy_return_type = unifier.get_dummy_var().0;
let dummy_return_type = unifier.get_dummy_var().ty;
type_var_to_concrete_def.insert(dummy_return_type, annotation.clone());
dummy_return_type
} else {
// if do not have return annotation, return none
// for uniform handling, still use type annotation
let dummy_return_type = unifier.get_dummy_var().0;
let dummy_return_type = unifier.get_dummy_var().ty;
type_var_to_concrete_def.insert(
dummy_return_type,
TypeAnnotation::Primitive(primitives.none),
@ -1286,7 +1288,7 @@ impl TopLevelComposer {
ast::StmtKind::AnnAssign { target, annotation, value: None, .. } => {
if let ast::ExprKind::Name { id: attr, .. } = &target.node {
if defined_fields.insert(attr.to_string()) {
let dummy_field_type = unifier.get_dummy_var().0;
let dummy_field_type = unifier.get_dummy_var().ty;
// handle Kernel[T], KernelInvariant[T]
let (annotation, mutable) = match &annotation.node {
@ -1749,7 +1751,7 @@ impl TopLevelComposer {
unreachable!()
};
let rigid = unifier.get_fresh_rigid_var(*name, *loc).0;
let rigid = unifier.get_fresh_rigid_var(*name, *loc).ty;
no_ranges.push(rigid);
vec![rigid]
})

View File

@ -2,7 +2,7 @@ use std::convert::TryInto;
use crate::symbol_resolver::SymbolValue;
use crate::toplevel::numpy::unpack_ndarray_var_tys;
use crate::typecheck::typedef::{Mapping, VarMap};
use crate::typecheck::typedef::{to_var_map, Mapping, TypeVarId, VarMap};
use nac3parser::ast::{Constant, Location};
use strum::IntoEnumIterator;
use strum_macros::EnumIter;
@ -377,12 +377,12 @@ impl TopLevelComposer {
let is_some_type_fun_ty = unifier.add_ty(TypeEnum::TFunc(FunSignature {
args: vec![],
ret: bool,
vars: VarMap::from([(option_type_var.1, option_type_var.0)]),
vars: to_var_map([option_type_var]),
}));
let unwrap_fun_ty = unifier.add_ty(TypeEnum::TFunc(FunSignature {
args: vec![],
ret: option_type_var.0,
vars: VarMap::from([(option_type_var.1, option_type_var.0)]),
ret: option_type_var.ty,
vars: to_var_map([option_type_var]),
}));
let option = unifier.add_ty(TypeEnum::TObj {
obj_id: PrimDef::Option.id(),
@ -393,7 +393,7 @@ impl TopLevelComposer {
]
.into_iter()
.collect::<HashMap<_, _>>(),
params: VarMap::from([(option_type_var.1, option_type_var.0)]),
params: to_var_map([option_type_var]),
});
let size_t_ty = match size_t {
@ -408,23 +408,17 @@ impl TopLevelComposer {
let ndarray_copy_fun_ret_ty = unifier.get_fresh_var(None, None);
let ndarray_copy_fun_ty = unifier.add_ty(TypeEnum::TFunc(FunSignature {
args: vec![],
ret: ndarray_copy_fun_ret_ty.0,
vars: VarMap::from([
(ndarray_dtype_tvar.1, ndarray_dtype_tvar.0),
(ndarray_ndims_tvar.1, ndarray_ndims_tvar.0),
]),
ret: ndarray_copy_fun_ret_ty.ty,
vars: to_var_map([ndarray_dtype_tvar, ndarray_ndims_tvar]),
}));
let ndarray_fill_fun_ty = unifier.add_ty(TypeEnum::TFunc(FunSignature {
args: vec![FuncArg {
name: "value".into(),
ty: ndarray_dtype_tvar.0,
ty: ndarray_dtype_tvar.ty,
default_value: None,
}],
ret: none,
vars: VarMap::from([
(ndarray_dtype_tvar.1, ndarray_dtype_tvar.0),
(ndarray_ndims_tvar.1, ndarray_ndims_tvar.0),
]),
vars: to_var_map([ndarray_dtype_tvar, ndarray_ndims_tvar]),
}));
let ndarray = unifier.add_ty(TypeEnum::TObj {
obj_id: PrimDef::NDArray.id(),
@ -432,13 +426,10 @@ impl TopLevelComposer {
(PrimDef::NDArrayCopy.simple_name().into(), (ndarray_copy_fun_ty, true)),
(PrimDef::NDArrayFill.simple_name().into(), (ndarray_fill_fun_ty, true)),
]),
params: VarMap::from([
(ndarray_dtype_tvar.1, ndarray_dtype_tvar.0),
(ndarray_ndims_tvar.1, ndarray_ndims_tvar.0),
]),
params: to_var_map([ndarray_dtype_tvar, ndarray_ndims_tvar]),
});
unifier.unify(ndarray_copy_fun_ret_ty.0, ndarray).unwrap();
unifier.unify(ndarray_copy_fun_ret_ty.ty, ndarray).unwrap();
let primitives = PrimitiveStore {
int32,
@ -583,7 +574,7 @@ impl TopLevelComposer {
}
/// get the `var_id` of a given `TVar` type
pub fn get_var_id(var_ty: Type, unifier: &mut Unifier) -> Result<u32, HashSet<String>> {
pub fn get_var_id(var_ty: Type, unifier: &mut Unifier) -> Result<TypeVarId, HashSet<String>> {
if let TypeEnum::TVar { id, .. } = unifier.get_ty(var_ty).as_ref() {
Ok(*id)
} else {

View File

@ -14,7 +14,10 @@ use super::typecheck::typedef::{
use crate::{
codegen::CodeGenerator,
symbol_resolver::{SymbolResolver, ValueEnum},
typecheck::{type_inferencer::CodeLocation, typedef::CallId},
typecheck::{
type_inferencer::CodeLocation,
typedef::{CallId, TypeVarId},
},
};
use inkwell::values::BasicValueEnum;
use itertools::{izip, Itertools};
@ -119,7 +122,7 @@ pub enum TopLevelDef {
/// Function signature.
signature: Type,
/// Instantiated type variable IDs.
var_id: Vec<u32>,
var_id: Vec<TypeVarId>,
/// Function instance to symbol mapping
///
/// * Key: String representation of type variable values, sorted by variable ID in ascending

View File

@ -2,7 +2,7 @@ use crate::{
toplevel::helper::PrimDef,
typecheck::{
type_inferencer::PrimitiveStore,
typedef::{Type, TypeEnum, Unifier, VarMap},
typedef::{Type, TypeEnum, TypeVarId, Unifier, VarMap},
},
};
use itertools::Itertools;
@ -57,7 +57,7 @@ pub fn subst_ndarray_tvars(
unifier.subst(ndarray, &tvar_subst).unwrap_or(ndarray)
}
fn unpack_ndarray_tvars(unifier: &mut Unifier, ndarray: Type) -> Vec<(u32, Type)> {
fn unpack_ndarray_tvars(unifier: &mut Unifier, ndarray: Type) -> Vec<(TypeVarId, Type)> {
let TypeEnum::TObj { obj_id, params, .. } = &*unifier.get_ty_immutable(ndarray) else {
panic!("Expected `ndarray` to be TObj, but got {}", unifier.stringify(ndarray))
};
@ -74,7 +74,7 @@ fn unpack_ndarray_tvars(unifier: &mut Unifier, ndarray: Type) -> Vec<(u32, Type)
/// Unpacks the type variable IDs of `ndarray` into a tuple. The elements of the tuple corresponds
/// to `dtype` (the element type) and `ndims` (the number of dimensions) of the `ndarray`
/// respectively.
pub fn unpack_ndarray_var_ids(unifier: &mut Unifier, ndarray: Type) -> (u32, u32) {
pub fn unpack_ndarray_var_ids(unifier: &mut Unifier, ndarray: Type) -> (TypeVarId, TypeVarId) {
unpack_ndarray_tvars(unifier, ndarray).into_iter().map(|v| v.0).collect_tuple().unwrap()
}

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: [239]\n}\n",
"Function {\nname: \"Generic_A.fun\",\nsig: \"fn[[a:int32], V]\",\nvar_id: [TypeVarId(239)]\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

@ -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: [241]\n}\n",
"Function {\nname: \"A.fun\",\nsig: \"fn[[a:T], V]\",\nvar_id: [246]\n}\n",
"Function {\nname: \"A.__init__\",\nsig: \"fn[[v:V], none]\",\nvar_id: [TypeVarId(241)]\n}\n",
"Function {\nname: \"A.fun\",\nsig: \"fn[[a:T], V]\",\nvar_id: [TypeVarId(246)]\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",
"Function {\nname: \"B.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\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: [247]\n}\n",
"Function {\nname: \"A.foo\",\nsig: \"fn[[a:T, b:V], none]\",\nvar_id: [TypeVarId(247)]\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: [255]\n}\n",
"Function {\nname: \"ff\",\nsig: \"fn[[a:T], V]\",\nvar_id: [TypeVarId(255)]\n}\n",
]

View File

@ -782,11 +782,11 @@ fn make_internal_resolver_with_tvar(
.into_iter()
.map(|(name, range)| {
(name, {
let (ty, id) = unifier.get_fresh_var_with_range(range.as_slice(), None, None);
let tvar = unifier.get_fresh_var_with_range(range.as_slice(), None, None);
if print {
println!("{}: {:?}, typevar{}", name, ty, id);
println!("{}: {:?}, typevar{}", name, tvar.ty, tvar.id);
}
ty
tvar.ty
})
})
.collect::<HashMap<_, _>>()

View File

@ -123,7 +123,7 @@ pub fn parse_ast_to_type_annotation_kinds<T, S: std::hash::BuildHasher + Clone>(
Ok(TypeAnnotation::CustomClass { id: obj_id, params: vec![] })
} else if let Ok(ty) = resolver.get_symbol_type(unifier, top_level_defs, primitives, *id) {
if let TypeEnum::TVar { .. } = unifier.get_ty(ty).as_ref() {
let var = unifier.get_fresh_var(Some(*id), Some(expr.location)).0;
let var = unifier.get_fresh_var(Some(*id), Some(expr.location)).ty;
unifier.unify(var, ty).unwrap();
Ok(TypeAnnotation::TypeVar(ty))
} else {
@ -426,7 +426,7 @@ pub fn get_type_from_type_annotation_kinds(
*name,
*loc,
);
unifier.unify(temp.0, p).is_ok()
unifier.unify(temp.ty, p).is_ok()
}
};
if ok {
@ -451,7 +451,7 @@ pub fn get_type_from_type_annotation_kinds(
// create a temp type var and unify to check compatibility
p == *tvar || {
let temp = unifier.get_fresh_const_generic_var(ty, *name, *loc);
unifier.unify(temp.0, p).is_ok()
unifier.unify(temp.ty, p).is_ok()
}
};
if ok {

View File

@ -103,8 +103,8 @@ pub fn impl_binop(
let (other_ty, other_var_id) = if other_ty.len() == 1 {
(other_ty[0], None)
} else {
let (ty, var_id) = unifier.get_fresh_var_with_range(other_ty, Some("N".into()), None);
(ty, Some(var_id))
let tvar = unifier.get_fresh_var_with_range(other_ty, Some("N".into()), None);
(tvar.ty, Some(tvar.id))
};
let function_vars = if let Some(var_id) = other_var_id {
@ -113,7 +113,7 @@ pub fn impl_binop(
VarMap::new()
};
let ret_ty = ret_ty.unwrap_or_else(|| unifier.get_fresh_var(None, None).0);
let ret_ty = ret_ty.unwrap_or_else(|| unifier.get_fresh_var(None, None).ty);
for op in ops {
fields.insert(binop_name(*op).into(), {
@ -151,7 +151,7 @@ pub fn impl_binop(
pub fn impl_unaryop(unifier: &mut Unifier, ty: Type, ret_ty: Option<Type>, ops: &[Unaryop]) {
with_fields(unifier, ty, |unifier, fields| {
let ret_ty = ret_ty.unwrap_or_else(|| unifier.get_fresh_var(None, None).0);
let ret_ty = ret_ty.unwrap_or_else(|| unifier.get_fresh_var(None, None).ty);
for op in ops {
fields.insert(
@ -181,8 +181,8 @@ pub fn impl_cmpop(
let (other_ty, other_var_id) = if other_ty.len() == 1 {
(other_ty[0], None)
} else {
let (ty, var_id) = unifier.get_fresh_var_with_range(other_ty, Some("N".into()), None);
(ty, Some(var_id))
let tvar = unifier.get_fresh_var_with_range(other_ty, Some("N".into()), None);
(tvar.ty, Some(tvar.id))
};
let function_vars = if let Some(var_id) = other_var_id {
@ -191,7 +191,7 @@ pub fn impl_cmpop(
VarMap::new()
};
let ret_ty = ret_ty.unwrap_or_else(|| unifier.get_fresh_var(None, None).0);
let ret_ty = ret_ty.unwrap_or_else(|| unifier.get_fresh_var(None, None).ty);
for op in ops {
fields.insert(
@ -652,7 +652,7 @@ pub fn set_primitives_magic_methods(store: &PrimitiveStore, unifier: &mut Unifie
let ndarray_usized_ndims_tvar =
unifier.get_fresh_const_generic_var(size_t, Some("ndarray_ndims".into()), None);
let ndarray_unsized_t =
make_ndarray_ty(unifier, store, None, Some(ndarray_usized_ndims_tvar.0));
make_ndarray_ty(unifier, store, None, Some(ndarray_usized_ndims_tvar.ty));
let (ndarray_dtype_t, _) = unpack_ndarray_var_tys(unifier, ndarray_t);
let (ndarray_unsized_dtype_t, _) = unpack_ndarray_var_tys(unifier, ndarray_unsized_t);
impl_basic_arithmetic(

View File

@ -432,7 +432,7 @@ impl<'a> Fold<()> for Inferencer<'a> {
let enter = TypeEnum::TFunc(FunSignature {
args: vec![],
ret: item.optional_vars.as_ref().map_or_else(
|| self.unifier.get_dummy_var().0,
|| self.unifier.get_dummy_var().ty,
|var| var.custom.unwrap(),
),
vars: VarMap::default(),
@ -440,7 +440,7 @@ impl<'a> Fold<()> for Inferencer<'a> {
let enter = self.unifier.add_ty(enter);
let exit = TypeEnum::TFunc(FunSignature {
args: vec![],
ret: self.unifier.get_dummy_var().0,
ret: self.unifier.get_dummy_var().ty,
vars: VarMap::default(),
});
let exit = self.unifier.add_ty(exit);
@ -511,7 +511,7 @@ impl<'a> Fold<()> for Inferencer<'a> {
};
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).ty)
})
.collect::<VarMap>();
Some(self.unifier.subst(self.primitives.option, &var_map).unwrap())
@ -660,7 +660,7 @@ impl<'a> Inferencer<'a> {
}
}
}
let ret = ret.unwrap_or_else(|| self.unifier.get_dummy_var().0);
let ret = ret.unwrap_or_else(|| self.unifier.get_dummy_var().ty);
let call = self.unifier.add_call(Call {
posargs: params,
@ -706,11 +706,13 @@ impl<'a> Inferencer<'a> {
let fn_args: Vec<_> = args
.args
.iter()
.map(|v| (v.node.arg, self.unifier.get_fresh_var(Some(v.node.arg), Some(v.location)).0))
.map(|v| {
(v.node.arg, self.unifier.get_fresh_var(Some(v.node.arg), Some(v.location)).ty)
})
.collect();
let mut variable_mapping = self.variable_mapping.clone();
variable_mapping.extend(fn_args.iter().copied());
let ret = self.unifier.get_dummy_var().0;
let ret = self.unifier.get_dummy_var().ty;
let mut new_context = Inferencer {
function_data: self.function_data,
@ -849,7 +851,7 @@ impl<'a> Inferencer<'a> {
&arg,
)?
} else {
self.unifier.get_dummy_var().0
self.unifier.get_dummy_var().ty
};
self.virtual_checks.push((arg0.custom.unwrap(), ty, *func_location));
let custom = Some(self.unifier.add_ty(TypeEnum::TVirtual { ty }));
@ -1362,7 +1364,7 @@ impl<'a> Inferencer<'a> {
}
}
let ret = self.unifier.get_dummy_var().0;
let ret = self.unifier.get_dummy_var().ty;
let call = self.unifier.add_call(Call {
posargs: args.iter().map(|v| v.custom.unwrap()).collect(),
kwargs: keywords
@ -1391,7 +1393,7 @@ impl<'a> Inferencer<'a> {
.resolver
.get_symbol_type(unifier, &self.top_level.definitions.read(), self.primitives, id)
.unwrap_or_else(|_| {
let ty = unifier.get_dummy_var().0;
let ty = unifier.get_dummy_var().ty;
variable_mapping.insert(id, ty);
ty
})
@ -1420,13 +1422,13 @@ impl<'a> Inferencer<'a> {
ast::Constant::None => {
report_error("CPython `None` not supported (nac3 uses `none` instead)", *loc)
}
ast::Constant::Ellipsis => Ok(self.unifier.get_fresh_var(None, None).0),
ast::Constant::Ellipsis => Ok(self.unifier.get_fresh_var(None, None).ty),
_ => report_error("not supported", *loc),
}
}
fn infer_list(&mut self, elts: &[ast::Expr<Option<Type>>]) -> InferenceResult {
let ty = self.unifier.get_dummy_var().0;
let ty = self.unifier.get_dummy_var().ty;
for t in elts {
self.unify(ty, t.custom.unwrap(), &t.location)?;
}
@ -1462,7 +1464,7 @@ impl<'a> Inferencer<'a> {
}
}
} else {
let attr_ty = self.unifier.get_dummy_var().0;
let attr_ty = self.unifier.get_dummy_var().ty;
let fields = once((
attr.into(),
RecordField::new(attr_ty, ctx == ExprContext::Store, Some(value.location)),
@ -1655,7 +1657,7 @@ impl<'a> Inferencer<'a> {
slice: &ast::Expr<Option<Type>>,
ctx: ExprContext,
) -> InferenceResult {
let ty = self.unifier.get_dummy_var().0;
let ty = self.unifier.get_dummy_var().ty;
match &slice.node {
ExprKind::Slice { lower, upper, step } => {
for v in [lower.as_ref(), upper.as_ref(), step.as_ref()].iter().flatten() {
@ -1759,7 +1761,7 @@ impl<'a> Inferencer<'a> {
let valid_index_ty = self
.unifier
.get_fresh_var_with_range(valid_index_tys.as_slice(), None, None)
.0;
.ty;
self.constrain(slice.custom.unwrap(), valid_index_ty, &slice.location)?;
self.infer_subscript_ndarray(value, ty, ndims)
}

View File

@ -143,10 +143,7 @@ impl TestEnvironment {
let ndarray = unifier.add_ty(TypeEnum::TObj {
obj_id: PrimDef::NDArray.id(),
fields: HashMap::new(),
params: VarMap::from([
(ndarray_dtype_tvar.1, ndarray_dtype_tvar.0),
(ndarray_ndims_tvar.1, ndarray_ndims_tvar.0),
]),
params: to_var_map([ndarray_dtype_tvar, ndarray_ndims_tvar]),
});
let primitives = PrimitiveStore {
int32,
@ -321,19 +318,19 @@ impl TestEnvironment {
unifier.put_primitive_store(&primitives);
let (v0, id) = unifier.get_dummy_var();
let tvar = unifier.get_dummy_var();
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::<VarMap>(),
fields: [("a".into(), (tvar.ty, true))].iter().cloned().collect::<HashMap<_, _>>(),
params: to_var_map([tvar]),
});
top_level_defs.push(
RwLock::new(TopLevelDef::Class {
name: "Foo".into(),
object_id: DefinitionId(defs + 1),
type_vars: vec![v0],
fields: [("a".into(), v0, true)].into(),
type_vars: vec![tvar.ty],
fields: [("a".into(), tvar.ty, true)].into(),
methods: Default::default(),
ancestors: Default::default(),
resolver: None,
@ -348,7 +345,7 @@ impl TestEnvironment {
unifier.add_ty(TypeEnum::TFunc(FunSignature {
args: vec![],
ret: foo_ty,
vars: [(id, v0)].iter().cloned().collect(),
vars: to_var_map([tvar]),
})),
);

View File

@ -2,7 +2,7 @@ use indexmap::IndexMap;
use itertools::Itertools;
use std::cell::RefCell;
use std::collections::HashMap;
use std::fmt::Display;
use std::fmt::{self, Display};
use std::iter::zip;
use std::rc::Rc;
use std::sync::{Arc, Mutex};
@ -28,8 +28,44 @@ pub struct CallId(pub(super) usize);
pub type Mapping<K, V = Type> = HashMap<K, V>;
pub type IndexMapping<K, V = Type> = IndexMap<K, V>;
/// The mapping between type variable ID and [unifier type][`Type`].
pub type VarMap = IndexMapping<u32>;
/// ID of a Python type variable. Specific to `nac3core`.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct TypeVarId(pub u32);
impl fmt::Display for TypeVarId {
// NOTE: Must output the string fo the ID value. Certain unit tests rely on string comparisons.
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_fmt(format_args!("{}", self.0))
}
}
/// A Python type variable. Used by `nac3core` during type inference.
#[derive(Debug, Clone, Copy)]
pub struct TypeVar {
/// `nac3core`'s internal [`TypeVarId`] of this type variable.
pub id: TypeVarId,
/// The assigned [`Type`] of this Python type variable.
pub ty: Type,
}
/// The mapping between [`TypeVarId`] and [unifier type][`Type`].
pub type VarMap = IndexMapping<TypeVarId>;
/// Build a [`VarMap`] from an iterator of [`TypeVar`]
///
/// The resulting [`VarMap`] wil have the same order as the input iterator.
pub fn to_var_map<I>(vars: I) -> VarMap
where
I: IntoIterator<Item = TypeVar>,
{
vars.into_iter().map(|var| (var.id, var.ty)).collect()
}
/// Get an iterator of [`TypeVar`]s from a [`VarMap`]
pub fn iter_type_vars(var_map: &VarMap) -> impl Iterator<Item = TypeVar> + '_ {
var_map.iter().map(|(&id, &ty)| TypeVar { id, ty })
}
#[derive(Clone)]
pub struct Call {
@ -127,14 +163,14 @@ impl RecordField {
#[derive(Clone)]
pub enum TypeEnum {
TRigidVar {
id: u32,
id: TypeVarId,
name: Option<StrRef>,
loc: Option<Location>,
},
/// A type variable.
TVar {
id: u32,
id: TypeVarId,
// empty indicates this is not a struct/tuple/list
fields: Option<Mapping<RecordKey, RecordField>>,
// empty indicates no restriction
@ -295,7 +331,7 @@ impl Unifier {
}
pub fn add_record(&mut self, fields: Mapping<RecordKey, RecordField>) -> Type {
let id = self.var_id + 1;
let id = TypeVarId(self.var_id + 1);
self.var_id += 1;
self.add_ty(TypeEnum::TVar {
id,
@ -346,24 +382,21 @@ impl Unifier {
self.unification_table.probe_value_immutable(a).clone()
}
pub fn get_fresh_rigid_var(
&mut self,
name: Option<StrRef>,
loc: Option<Location>,
) -> (Type, u32) {
let id = self.var_id + 1;
pub fn get_fresh_rigid_var(&mut self, name: Option<StrRef>, loc: Option<Location>) -> TypeVar {
let id = TypeVarId(self.var_id + 1);
self.var_id += 1;
(self.add_ty(TypeEnum::TRigidVar { id, name, loc }), id)
let ty = self.add_ty(TypeEnum::TRigidVar { id, name, loc });
TypeVar { id, ty }
}
pub fn get_dummy_var(&mut self) -> (Type, u32) {
pub fn get_dummy_var(&mut self) -> TypeVar {
self.get_fresh_var_with_range(&[], None, None)
}
/// Returns a fresh [type variable][TypeEnum::TVar] with no associated range.
///
/// This type variable can be instantiated by any type.
pub fn get_fresh_var(&mut self, name: Option<StrRef>, loc: Option<Location>) -> (Type, u32) {
pub fn get_fresh_var(&mut self, name: Option<StrRef>, loc: Option<Location>) -> TypeVar {
self.get_fresh_var_with_range(&[], name, loc)
}
@ -375,21 +408,20 @@ impl Unifier {
range: &[Type],
name: Option<StrRef>,
loc: Option<Location>,
) -> (Type, u32) {
let id = self.var_id + 1;
self.var_id += 1;
) -> TypeVar {
let range = range.to_vec();
(
self.add_ty(TypeEnum::TVar {
let id = TypeVarId(self.var_id + 1);
self.var_id += 1;
let ty = self.add_ty(TypeEnum::TVar {
id,
range,
fields: None,
name,
loc,
is_const_generic: false,
}),
id,
)
});
TypeVar { id, ty }
}
/// Returns a fresh type representing a constant generic variable with the given underlying type `ty`.
@ -398,20 +430,18 @@ impl Unifier {
ty: Type,
name: Option<StrRef>,
loc: Option<Location>,
) -> (Type, u32) {
let id = self.var_id + 1;
) -> TypeVar {
let id = TypeVarId(self.var_id + 1);
self.var_id += 1;
(
self.add_ty(TypeEnum::TVar {
let ty = self.add_ty(TypeEnum::TVar {
id,
range: vec![ty],
fields: None,
name,
loc,
is_const_generic: true,
}),
id,
)
});
TypeVar { id, ty }
}
/// Returns a fresh type representing a [literal][TypeEnum::TConstant] with the given `values`.
@ -464,7 +494,7 @@ impl Unifier {
}
}
TypeEnum::TObj { params, .. } => {
let (keys, params): (Vec<u32>, Vec<Type>) = params.iter().unzip();
let (keys, params): (Vec<TypeVarId>, Vec<Type>) = params.iter().unzip();
let params = params
.into_iter()
.map(|ty| self.get_instantiations(ty).unwrap_or_else(|| vec![ty]))
@ -1014,7 +1044,7 @@ impl Unifier {
pub fn stringify_with_notes(
&self,
ty: Type,
notes: &mut Option<HashMap<u32, String>>,
notes: &mut Option<HashMap<TypeVarId, String>>,
) -> String {
let top_level = self.top_level.clone();
self.internal_stringify(
@ -1043,11 +1073,11 @@ impl Unifier {
ty: Type,
obj_to_name: &mut F,
var_to_name: &mut G,
notes: &mut Option<HashMap<u32, String>>,
notes: &mut Option<HashMap<TypeVarId, String>>,
) -> String
where
F: FnMut(usize) -> String,
G: FnMut(u32) -> String,
G: FnMut(TypeVarId) -> String,
{
let ty = self.unification_table.probe_value_immutable(ty).clone();
match ty.as_ref() {
@ -1182,7 +1212,7 @@ impl Unifier {
let mapping = vars
.into_iter()
.map(|(k, range, name, loc)| {
(k, self.get_fresh_var_with_range(range.as_ref(), name, loc).0)
(k, self.get_fresh_var_with_range(range.as_ref(), name, loc).ty)
})
.collect();
self.subst(ty, &mapping).unwrap_or(ty)
@ -1206,7 +1236,7 @@ impl Unifier {
let cached = cache.get_mut(&a);
if let Some(cached) = cached {
if cached.is_none() {
*cached = Some(self.get_fresh_var(None, None).0);
*cached = Some(self.get_fresh_var(None, None).ty);
}
return *cached;
}
@ -1361,7 +1391,7 @@ impl Unifier {
if range.is_empty() {
Err(())
} else {
let id = self.var_id + 1;
let id = TypeVarId(self.var_id + 1);
self.var_id += 1;
let ty = TVar {
id,

View File

@ -110,13 +110,13 @@ impl TestEnvironment {
params: VarMap::new(),
}),
);
let (v0, id) = unifier.get_dummy_var();
let tvar = unifier.get_dummy_var();
type_mapping.insert(
"Foo".into(),
unifier.add_ty(TypeEnum::TObj {
obj_id: DefinitionId(3),
fields: [("a".into(), (v0, true))].iter().cloned().collect::<HashMap<_, _>>(),
params: [(id, v0)].iter().cloned().collect::<VarMap>(),
fields: [("a".into(), (tvar.ty, true))].iter().cloned().collect::<HashMap<_, _>>(),
params: to_var_map([tvar]),
}),
);
@ -250,7 +250,7 @@ fn test_unify(
let mut mapping = HashMap::new();
for i in 1..=variable_count {
let v = env.unifier.get_dummy_var();
mapping.insert(format!("v{}", i), v.0);
mapping.insert(format!("v{}", i), v.ty);
}
// unification may have side effect when we do type resolution, so freeze the types
// before doing unification.
@ -315,7 +315,7 @@ fn test_invalid_unification(
let mut mapping = HashMap::new();
for i in 1..=variable_count {
let v = env.unifier.get_dummy_var();
mapping.insert(format!("v{}", i), v.0);
mapping.insert(format!("v{}", i), v.ty);
}
// unification may have side effect when we do type resolution, so freeze the types
// before doing unification.
@ -369,8 +369,8 @@ fn test_virtual() {
.collect::<HashMap<StrRef, _>>(),
params: VarMap::new(),
});
let v0 = env.unifier.get_dummy_var().0;
let v1 = env.unifier.get_dummy_var().0;
let v0 = env.unifier.get_dummy_var().ty;
let v1 = env.unifier.get_dummy_var().ty;
let a = env.unifier.add_ty(TypeEnum::TVirtual { ty: bar });
let b = env.unifier.add_ty(TypeEnum::TVirtual { ty: v0 });
@ -403,12 +403,12 @@ fn test_typevar_range() {
// unification between v and int
// where v in (int, bool)
let v = env.unifier.get_fresh_var_with_range(&[int, boolean], None, None).0;
let v = env.unifier.get_fresh_var_with_range(&[int, boolean], None, None).ty;
env.unifier.unify(int, v).unwrap();
// unification between v and list[int]
// where v in (int, bool)
let v = env.unifier.get_fresh_var_with_range(&[int, boolean], None, None).0;
let v = env.unifier.get_fresh_var_with_range(&[int, boolean], None, None).ty;
assert_eq!(
env.unify(int_list, v),
Err("Expected any one of these types: 0, 2, but got list[0]".to_string())
@ -416,25 +416,25 @@ fn test_typevar_range() {
// unification between v and float
// where v in (int, bool)
let v = env.unifier.get_fresh_var_with_range(&[int, boolean], None, None).0;
let v = env.unifier.get_fresh_var_with_range(&[int, boolean], None, None).ty;
assert_eq!(
env.unify(float, v),
Err("Expected any one of these types: 0, 2, but got 1".to_string())
);
let v1 = env.unifier.get_fresh_var_with_range(&[int, boolean], None, None).0;
let v1 = env.unifier.get_fresh_var_with_range(&[int, boolean], None, None).ty;
let v1_list = env.unifier.add_ty(TypeEnum::TList { ty: v1 });
let v = env.unifier.get_fresh_var_with_range(&[int, v1_list], None, None).0;
let v = env.unifier.get_fresh_var_with_range(&[int, v1_list], None, None).ty;
// unification between v and int
// where v in (int, list[v1]), v1 in (int, bool)
env.unifier.unify(int, v).unwrap();
let v = env.unifier.get_fresh_var_with_range(&[int, v1_list], None, None).0;
let v = env.unifier.get_fresh_var_with_range(&[int, v1_list], None, None).ty;
// unification between v and list[int]
// where v in (int, list[v1]), v1 in (int, bool)
env.unifier.unify(int_list, v).unwrap();
let v = env.unifier.get_fresh_var_with_range(&[int, v1_list], None, None).0;
let v = env.unifier.get_fresh_var_with_range(&[int, v1_list], None, None).ty;
// unification between v and list[float]
// where v in (int, list[v1]), v1 in (int, bool)
assert_eq!(
@ -442,30 +442,30 @@ fn test_typevar_range() {
Err("Expected any one of these types: 0, list[typevar5], but got list[1]\n\nNotes:\n typevar5 ∈ {0, 2}".to_string())
);
let a = env.unifier.get_fresh_var_with_range(&[int, float], None, None).0;
let b = env.unifier.get_fresh_var_with_range(&[boolean, float], None, None).0;
let a = env.unifier.get_fresh_var_with_range(&[int, float], None, None).ty;
let b = env.unifier.get_fresh_var_with_range(&[boolean, float], None, None).ty;
env.unifier.unify(a, b).unwrap();
env.unifier.unify(a, float).unwrap();
let a = env.unifier.get_fresh_var_with_range(&[int, float], None, None).0;
let b = env.unifier.get_fresh_var_with_range(&[boolean, float], None, None).0;
let a = env.unifier.get_fresh_var_with_range(&[int, float], None, None).ty;
let b = env.unifier.get_fresh_var_with_range(&[boolean, float], None, None).ty;
env.unifier.unify(a, b).unwrap();
assert_eq!(env.unify(a, int), Err("Expected any one of these types: 1, but got 0".into()));
let a = env.unifier.get_fresh_var_with_range(&[int, float], None, None).0;
let b = env.unifier.get_fresh_var_with_range(&[boolean, float], None, None).0;
let a = env.unifier.get_fresh_var_with_range(&[int, float], None, None).ty;
let b = env.unifier.get_fresh_var_with_range(&[boolean, float], None, None).ty;
let a_list = env.unifier.add_ty(TypeEnum::TList { ty: a });
let a_list = env.unifier.get_fresh_var_with_range(&[a_list], None, None).0;
let a_list = env.unifier.get_fresh_var_with_range(&[a_list], None, None).ty;
let b_list = env.unifier.add_ty(TypeEnum::TList { ty: b });
let b_list = env.unifier.get_fresh_var_with_range(&[b_list], None, None).0;
let b_list = env.unifier.get_fresh_var_with_range(&[b_list], None, None).ty;
env.unifier.unify(a_list, b_list).unwrap();
let float_list = env.unifier.add_ty(TypeEnum::TList { ty: float });
env.unifier.unify(a_list, float_list).unwrap();
// previous unifications should not affect a and b
env.unifier.unify(a, int).unwrap();
let a = env.unifier.get_fresh_var_with_range(&[int, float], None, None).0;
let b = env.unifier.get_fresh_var_with_range(&[boolean, float], None, None).0;
let a = env.unifier.get_fresh_var_with_range(&[int, float], None, None).ty;
let b = env.unifier.get_fresh_var_with_range(&[boolean, float], None, None).ty;
let a_list = env.unifier.add_ty(TypeEnum::TList { ty: a });
let b_list = env.unifier.add_ty(TypeEnum::TList { ty: b });
env.unifier.unify(a_list, b_list).unwrap();
@ -477,10 +477,10 @@ fn test_typevar_range() {
.into())
);
let a = env.unifier.get_fresh_var_with_range(&[int, float], None, None).0;
let b = env.unifier.get_dummy_var().0;
let a = env.unifier.get_fresh_var_with_range(&[int, float], None, None).ty;
let b = env.unifier.get_dummy_var().ty;
let a_list = env.unifier.add_ty(TypeEnum::TList { ty: a });
let a_list = env.unifier.get_fresh_var_with_range(&[a_list], None, None).0;
let a_list = env.unifier.get_fresh_var_with_range(&[a_list], None, None).ty;
let b_list = env.unifier.add_ty(TypeEnum::TList { ty: b });
env.unifier.unify(a_list, b_list).unwrap();
assert_eq!(
@ -492,9 +492,9 @@ fn test_typevar_range() {
#[test]
fn test_rigid_var() {
let mut env = TestEnvironment::new();
let a = env.unifier.get_fresh_rigid_var(None, None).0;
let b = env.unifier.get_fresh_rigid_var(None, None).0;
let x = env.unifier.get_dummy_var().0;
let a = env.unifier.get_fresh_rigid_var(None, None).ty;
let b = env.unifier.get_fresh_rigid_var(None, None).ty;
let x = env.unifier.get_dummy_var().ty;
let list_a = env.unifier.add_ty(TypeEnum::TList { ty: a });
let list_x = env.unifier.add_ty(TypeEnum::TList { ty: x });
let int = env.parse("int", &HashMap::new());
@ -522,13 +522,13 @@ fn test_instantiation() {
let obj_map: HashMap<_, _> =
[(0usize, "int"), (1, "float"), (2, "bool")].iter().cloned().collect();
let v = env.unifier.get_fresh_var_with_range(&[int, boolean], None, None).0;
let v = env.unifier.get_fresh_var_with_range(&[int, boolean], None, None).ty;
let list_v = env.unifier.add_ty(TypeEnum::TList { ty: v });
let v1 = env.unifier.get_fresh_var_with_range(&[list_v, int], None, None).0;
let v2 = env.unifier.get_fresh_var_with_range(&[list_int, float], None, None).0;
let t = env.unifier.get_dummy_var().0;
let v1 = env.unifier.get_fresh_var_with_range(&[list_v, int], None, None).ty;
let v2 = env.unifier.get_fresh_var_with_range(&[list_int, float], None, None).ty;
let t = env.unifier.get_dummy_var().ty;
let tuple = env.unifier.add_ty(TypeEnum::TTuple { ty: vec![v, v1, v2] });
let v3 = env.unifier.get_fresh_var_with_range(&[tuple, t], None, None).0;
let v3 = env.unifier.get_fresh_var_with_range(&[tuple, t], None, None).ty;
// t = TypeVar('t')
// v = TypeVar('v', int, bool)
// v1 = TypeVar('v1', 'list[v]', int)

View File

@ -124,7 +124,7 @@ fn handle_typevar_definition(
)]));
}
Ok(unifier.get_fresh_var_with_range(&constraints, Some(generic_name), Some(loc)).0)
Ok(unifier.get_fresh_var_with_range(&constraints, Some(generic_name), Some(loc)).ty)
}
ExprKind::Name { id, .. } if id == &"ConstGeneric".into() => {
@ -155,7 +155,7 @@ fn handle_typevar_definition(
get_type_from_type_annotation_kinds(def_list, unifier, &ty, &mut None)?;
let loc = func.location;
Ok(unifier.get_fresh_const_generic_var(constraint, Some(generic_name), Some(loc)).0)
Ok(unifier.get_fresh_const_generic_var(constraint, Some(generic_name), Some(loc)).ty)
}
_ => Err(HashSet::from([format!(