From fd83c9a739d807e6874163c6539c9b81a2fb126b Mon Sep 17 00:00:00 2001 From: microproofs Date: Mon, 10 Jul 2023 16:11:45 -0400 Subject: [PATCH] feat: fix up generic type functions to work with the new air tree functions chore: remove commented code --- crates/aiken-lang/src/gen_uplc/builder.rs | 10 +- crates/aiken-lang/src/gen_uplc2.rs | 42 ++--- crates/aiken-lang/src/gen_uplc2/builder.rs | 188 ++++++++++++++++++++- 3 files changed, 207 insertions(+), 33 deletions(-) diff --git a/crates/aiken-lang/src/gen_uplc/builder.rs b/crates/aiken-lang/src/gen_uplc/builder.rs index 48b46b8b..2744be77 100644 --- a/crates/aiken-lang/src/gen_uplc/builder.rs +++ b/crates/aiken-lang/src/gen_uplc/builder.rs @@ -2010,12 +2010,18 @@ pub fn special_case_builtin( pub fn get_arg_type_name(tipo: &Type) -> String { match tipo { - Type::App { name, .. } => name.clone(), + 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 { .. } => "".to_string(), + Type::Tuple { elems } => { + let inner_args = elems.iter().map(|arg| get_arg_type_name(arg)).collect_vec(); + inner_args.join("_") + } _ => unreachable!(), } } diff --git a/crates/aiken-lang/src/gen_uplc2.rs b/crates/aiken-lang/src/gen_uplc2.rs index 98e5078b..5cea15e1 100644 --- a/crates/aiken-lang/src/gen_uplc2.rs +++ b/crates/aiken-lang/src/gen_uplc2.rs @@ -21,8 +21,8 @@ use crate::{ gen_uplc::{ air::Air, builder::{ - self as build, AssignmentProperties, ClauseProperties, DataTypeKey, FunctionAccessKey, - SpecificClause, + self as build, get_arg_type_name, AssignmentProperties, ClauseProperties, DataTypeKey, + FunctionAccessKey, SpecificClause, }, }, gen_uplc2::builder::convert_opaque_type, @@ -106,7 +106,7 @@ impl<'a> CodeGenerator<'a> { fn build(&mut self, body: &TypedExpr) -> AirTree { match body { - TypedExpr::Int { value, .. } => AirTree::int(value), + TypedExpr::UInt { value, .. } => AirTree::int(value), TypedExpr::String { value, .. } => AirTree::string(value), TypedExpr::ByteArray { bytes, .. } => AirTree::byte_array(bytes.clone()), TypedExpr::Sequence { expressions, .. } | TypedExpr::Pipeline { expressions, .. } => { @@ -544,7 +544,7 @@ impl<'a> CodeGenerator<'a> { Pattern::Var { name, .. } => { if props.full_check { let mut index_map = IndexMap::new(); - // let tipo = builder::convert_opaque_type(); + let tipo = convert_opaque_type(tipo, &self.data_types); let assignment = AirTree::let_assignment(name, value); let val = AirTree::local_var(name, tipo.clone()); @@ -552,7 +552,7 @@ impl<'a> CodeGenerator<'a> { AirTree::let_assignment(name, assignment.hoist_over(val)) } else { let expect = self.expect_type_assign( - tipo, + &tipo, val.clone(), &mut index_map, pattern.location(), @@ -575,14 +575,14 @@ impl<'a> CodeGenerator<'a> { if props.full_check { let name = &format!("__discard_expect_{}", name); let mut index_map = IndexMap::new(); - // let tipo = builder::convert_opaque_type(); + let tipo = convert_opaque_type(tipo, &self.data_types); let assignment = AirTree::let_assignment(name, value); let val = AirTree::local_var(name, tipo.clone()); if tipo.is_primitive() { AirTree::let_assignment(name, assignment.hoist_over(val)) } else { let expect = self.expect_type_assign( - tipo, + &tipo, val.clone(), &mut index_map, pattern.location(), @@ -1131,15 +1131,14 @@ impl<'a> CodeGenerator<'a> { unreachable!("We need a data type definition fot type {:#?}", tipo) }); - let mut tipo = convert_opaque_type(); - - // for (index, arg) in tipo.arg_types().unwrap().iter().enumerate() { - // let field_type = arg.clone(); - // type_map.insert(index, field_type); - // } + let mut data_type_variant = tipo + .get_inner_types() + .iter() + .map(|arg| get_arg_type_name(arg)) + .join("_"); // TODO calculate the variant name. - let data_type_name = format!("__expect_{}{}", data_type.name, ""); + let data_type_name = format!("__expect_{}_{}", data_type.name, data_type_variant); let function = self.code_gen_functions.get(&data_type_name); todo!(); if function.is_none() && defined_data_types.get(&data_type_name).is_none() { @@ -1152,7 +1151,7 @@ impl<'a> CodeGenerator<'a> { let func_var = AirTree::var( ValueConstructor::public( - tipo, + tipo.clone(), ValueConstructorVariant::ModuleFn { name: data_type_name.to_string(), field_map: None, @@ -1846,7 +1845,6 @@ impl<'a> CodeGenerator<'a> { Pattern::Discard { .. } => AirTree::no_op(), Pattern::List { elements, tail, .. } => { props.complex_clause = true; - // let item_name = format!("__list_item_id_{}", self.id_gen.next()); let tail_name_base = "__tail".to_string(); if elements.is_empty() { @@ -1881,18 +1879,6 @@ impl<'a> CodeGenerator<'a> { format!("{}_{}", tail_name_base, index - 1) }; - // let mut clause_properties = ClauseProperties { - // clause_var_name: item_name.clone(), - // needs_constr_var: false, - // complex_clause: false, - // original_subject_name: item_name.clone(), - // specific_clause: SpecificClause::ListClause { - // current_index: index as i64, - // defined_tails: vec![], - // }, - // final_clause, - // }; - let tail_name = format!("{tail_name_base}_{index}"); if elements.len() - 1 == index { diff --git a/crates/aiken-lang/src/gen_uplc2/builder.rs b/crates/aiken-lang/src/gen_uplc2/builder.rs index d33166bc..d2bad701 100644 --- a/crates/aiken-lang/src/gen_uplc2/builder.rs +++ b/crates/aiken-lang/src/gen_uplc2/builder.rs @@ -1,4 +1,11 @@ -use crate::builtins::bool; +use indexmap::IndexMap; + +use crate::{ + ast::TypedDataType, + builtins::bool, + gen_uplc::builder::{lookup_data_type_by_tipo, DataTypeKey}, + tipo::TypeVar, +}; use std::sync::Arc; use crate::{ @@ -8,8 +15,183 @@ use crate::{ use super::tree::AirTree; -pub fn convert_opaque_type() -> Arc { - todo!() +pub fn get_generic_id_and_type(tipo: &Type, param: &Type) -> Vec<(u64, Arc)> { + 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 convert_opaque_type( + t: &Arc, + data_types: &IndexMap, +) -> Arc { + 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 mono_types: IndexMap>; + 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)); + } + 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); + + convert_opaque_type(&mono_type, data_types) + } 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); + 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); + new_args.push(arg); + } + + let ret = convert_opaque_type(ret, data_types); + + 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) + } else { + t.clone() + } + } + Type::Tuple { elems } => { + let mut new_elems = vec![]; + for arg in elems { + let arg = convert_opaque_type(arg, data_types); + new_elems.push(arg); + } + Type::Tuple { elems: new_elems }.into() + } + } + } +} + +pub fn check_replaceable_opaque_type( + t: &Arc, + data_types: &IndexMap, +) -> bool { + let data_type = lookup_data_type_by_tipo(data_types, t); + + if let Some(data_type) = data_type { + 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: &Arc, + mono_types: &IndexMap>, +) -> Arc { + 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); + tipo + } + TypeVar::Generic { .. } | TypeVar::Unbound { .. } => unreachable!(), + } + } + } + } else { + tipo.clone() + } } pub fn constants_ir(literal: &Constant) -> AirTree {