Handle (recursive) generic types during reification.
Also moved a bunch of functions from code-gen back into _tipo_, as they're better suited and generic enough to be reused elsewhere.
This commit is contained in:
@@ -4,14 +4,18 @@ use super::{
|
||||
};
|
||||
use crate::{
|
||||
ast::{
|
||||
AssignmentKind, BinOp, ClauseGuard, Constant, DataType, DataTypeKey, FunctionAccessKey,
|
||||
Pattern, Span, TraceLevel, TypedArg, TypedClause, TypedClauseGuard, TypedDataType,
|
||||
TypedPattern, UnOp,
|
||||
AssignmentKind, BinOp, ClauseGuard, Constant, DataTypeKey, FunctionAccessKey, Pattern,
|
||||
Span, TraceLevel, TypedArg, TypedClause, TypedClauseGuard, TypedDataType, TypedPattern,
|
||||
UnOp,
|
||||
},
|
||||
builtins::{bool, data, function, int, list, string, void},
|
||||
expr::TypedExpr,
|
||||
line_numbers::{LineColumn, LineNumbers},
|
||||
tipo::{PatternConstructor, Type, TypeVar, ValueConstructor, ValueConstructorVariant},
|
||||
tipo::{
|
||||
check_replaceable_opaque_type, convert_opaque_type, find_and_replace_generics,
|
||||
lookup_data_type_by_tipo, PatternConstructor, Type, ValueConstructor,
|
||||
ValueConstructorVariant,
|
||||
},
|
||||
};
|
||||
use indexmap::{IndexMap, IndexSet};
|
||||
use itertools::{Itertools, Position};
|
||||
@@ -274,239 +278,6 @@ impl Default for CodeGenSpecialFuncs {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_generic_id_and_type(tipo: &Type, param: &Type) -> Vec<(u64, Rc<Type>)> {
|
||||
let mut generics_ids = vec![];
|
||||
|
||||
if let Some(id) = tipo.get_generic() {
|
||||
generics_ids.push((id, param.clone().into()));
|
||||
return generics_ids;
|
||||
}
|
||||
|
||||
for (tipo, param_type) in tipo
|
||||
.get_inner_types()
|
||||
.iter()
|
||||
.zip(param.get_inner_types().iter())
|
||||
{
|
||||
generics_ids.append(&mut get_generic_id_and_type(tipo, param_type));
|
||||
}
|
||||
generics_ids
|
||||
}
|
||||
|
||||
pub fn lookup_data_type_by_tipo(
|
||||
data_types: &IndexMap<&DataTypeKey, &TypedDataType>,
|
||||
tipo: &Type,
|
||||
) -> Option<DataType<Rc<Type>>> {
|
||||
match tipo {
|
||||
Type::Fn { ret, .. } => match ret.as_ref() {
|
||||
Type::App { module, name, .. } => {
|
||||
let data_type_key = DataTypeKey {
|
||||
module_name: module.clone(),
|
||||
defined_type: name.clone(),
|
||||
};
|
||||
data_types.get(&data_type_key).map(|item| (*item).clone())
|
||||
}
|
||||
_ => None,
|
||||
},
|
||||
Type::App { module, name, .. } => {
|
||||
let data_type_key = DataTypeKey {
|
||||
module_name: module.clone(),
|
||||
defined_type: name.clone(),
|
||||
};
|
||||
|
||||
data_types.get(&data_type_key).map(|item| (*item).clone())
|
||||
}
|
||||
Type::Var { tipo } => {
|
||||
if let TypeVar::Link { tipo } = &*tipo.borrow() {
|
||||
lookup_data_type_by_tipo(data_types, tipo)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_arg_type_name(tipo: &Type) -> String {
|
||||
match tipo {
|
||||
Type::App { name, args, .. } => {
|
||||
let inner_args = args.iter().map(|arg| get_arg_type_name(arg)).collect_vec();
|
||||
format!("{}_{}", name, inner_args.join("_"))
|
||||
}
|
||||
Type::Var { tipo } => match tipo.borrow().clone() {
|
||||
TypeVar::Link { tipo } => get_arg_type_name(tipo.as_ref()),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
Type::Tuple { elems } => {
|
||||
let inner_args = elems.iter().map(|arg| get_arg_type_name(arg)).collect_vec();
|
||||
inner_args.join("_")
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn convert_opaque_type(
|
||||
t: &Rc<Type>,
|
||||
data_types: &IndexMap<&DataTypeKey, &TypedDataType>,
|
||||
deep: bool,
|
||||
) -> Rc<Type> {
|
||||
if check_replaceable_opaque_type(t, data_types) && matches!(t.as_ref(), Type::App { .. }) {
|
||||
let data_type = lookup_data_type_by_tipo(data_types, t).unwrap();
|
||||
let new_type_fields = data_type.typed_parameters;
|
||||
|
||||
let mut mono_type_vec = vec![];
|
||||
|
||||
for (tipo, param) in new_type_fields.iter().zip(t.arg_types().unwrap()) {
|
||||
mono_type_vec.append(&mut get_generic_id_and_type(tipo, ¶m));
|
||||
}
|
||||
let mono_types = mono_type_vec.into_iter().collect();
|
||||
|
||||
let generic_type = &data_type.constructors[0].arguments[0].tipo;
|
||||
|
||||
let mono_type = find_and_replace_generics(generic_type, &mono_types);
|
||||
|
||||
if deep {
|
||||
convert_opaque_type(&mono_type, data_types, deep)
|
||||
} else {
|
||||
mono_type
|
||||
}
|
||||
} else {
|
||||
match t.as_ref() {
|
||||
Type::App {
|
||||
public,
|
||||
module,
|
||||
name,
|
||||
args,
|
||||
} => {
|
||||
let mut new_args = vec![];
|
||||
for arg in args {
|
||||
let arg = convert_opaque_type(arg, data_types, deep);
|
||||
new_args.push(arg);
|
||||
}
|
||||
Type::App {
|
||||
public: *public,
|
||||
module: module.clone(),
|
||||
name: name.clone(),
|
||||
args: new_args,
|
||||
}
|
||||
.into()
|
||||
}
|
||||
Type::Fn { args, ret } => {
|
||||
let mut new_args = vec![];
|
||||
for arg in args {
|
||||
let arg = convert_opaque_type(arg, data_types, deep);
|
||||
new_args.push(arg);
|
||||
}
|
||||
|
||||
let ret = convert_opaque_type(ret, data_types, deep);
|
||||
|
||||
Type::Fn {
|
||||
args: new_args,
|
||||
ret,
|
||||
}
|
||||
.into()
|
||||
}
|
||||
Type::Var { tipo: var_tipo } => {
|
||||
if let TypeVar::Link { tipo } = &var_tipo.borrow().clone() {
|
||||
convert_opaque_type(tipo, data_types, deep)
|
||||
} else {
|
||||
t.clone()
|
||||
}
|
||||
}
|
||||
Type::Tuple { elems } => {
|
||||
let mut new_elems = vec![];
|
||||
for arg in elems {
|
||||
let arg = convert_opaque_type(arg, data_types, deep);
|
||||
new_elems.push(arg);
|
||||
}
|
||||
Type::Tuple { elems: new_elems }.into()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check_replaceable_opaque_type(
|
||||
t: &Type,
|
||||
data_types: &IndexMap<&DataTypeKey, &TypedDataType>,
|
||||
) -> bool {
|
||||
let data_type = lookup_data_type_by_tipo(data_types, t);
|
||||
|
||||
if let Some(data_type) = data_type {
|
||||
assert!(!data_type.constructors.is_empty());
|
||||
let data_type_args = &data_type.constructors[0].arguments;
|
||||
data_type_args.len() == 1 && data_type.opaque && data_type.constructors.len() == 1
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
pub fn find_and_replace_generics(
|
||||
tipo: &Rc<Type>,
|
||||
mono_types: &IndexMap<u64, Rc<Type>>,
|
||||
) -> Rc<Type> {
|
||||
if let Some(id) = tipo.get_generic() {
|
||||
// If a generic does not have a type we know of
|
||||
// like a None in option then just use same type
|
||||
mono_types.get(&id).unwrap_or(tipo).clone()
|
||||
} else if tipo.is_generic() {
|
||||
match &**tipo {
|
||||
Type::App {
|
||||
args,
|
||||
public,
|
||||
module,
|
||||
name,
|
||||
} => {
|
||||
let mut new_args = vec![];
|
||||
for arg in args {
|
||||
let arg = find_and_replace_generics(arg, mono_types);
|
||||
new_args.push(arg);
|
||||
}
|
||||
let t = Type::App {
|
||||
args: new_args,
|
||||
public: *public,
|
||||
module: module.clone(),
|
||||
name: name.clone(),
|
||||
};
|
||||
t.into()
|
||||
}
|
||||
Type::Fn { args, ret } => {
|
||||
let mut new_args = vec![];
|
||||
for arg in args {
|
||||
let arg = find_and_replace_generics(arg, mono_types);
|
||||
new_args.push(arg);
|
||||
}
|
||||
|
||||
let ret = find_and_replace_generics(ret, mono_types);
|
||||
|
||||
let t = Type::Fn {
|
||||
args: new_args,
|
||||
ret,
|
||||
};
|
||||
|
||||
t.into()
|
||||
}
|
||||
Type::Tuple { elems } => {
|
||||
let mut new_elems = vec![];
|
||||
for elem in elems {
|
||||
let elem = find_and_replace_generics(elem, mono_types);
|
||||
new_elems.push(elem);
|
||||
}
|
||||
let t = Type::Tuple { elems: new_elems };
|
||||
t.into()
|
||||
}
|
||||
Type::Var { tipo: var_tipo } => {
|
||||
let var_type = var_tipo.as_ref().borrow().clone();
|
||||
|
||||
match var_type {
|
||||
TypeVar::Link { tipo } => find_and_replace_generics(&tipo, mono_types),
|
||||
TypeVar::Generic { .. } | TypeVar::Unbound { .. } => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
tipo.clone()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn constants_ir(literal: &Constant) -> AirTree {
|
||||
match literal {
|
||||
Constant::Int { value, .. } => AirTree::int(value),
|
||||
|
||||
Reference in New Issue
Block a user