Preserve TypeAlias in types for better context/feedback.

This commit is contained in:
KtorZ 2024-03-08 12:46:42 +01:00
parent 877d10ef22
commit ed9f5c6ef7
No known key found for this signature in database
GPG Key ID: 33173CB6F77F4277
13 changed files with 420 additions and 201 deletions

View File

@ -1197,7 +1197,7 @@ impl TypedPattern {
| Pattern::Tuple { | Pattern::Tuple {
elems: elements, .. elems: elements, ..
} => match &**value { } => match &**value {
Type::Tuple { elems } => elements Type::Tuple { elems, .. } => elements
.iter() .iter()
.zip(elems.iter()) .zip(elems.iter())
.find_map(|(e, t)| e.find_node(byte_index, t)) .find_map(|(e, t)| e.find_node(byte_index, t))

View File

@ -1270,6 +1270,7 @@ pub fn int() -> Rc<Type> {
name: INT.to_string(), name: INT.to_string(),
module: "".to_string(), module: "".to_string(),
args: vec![], args: vec![],
alias: None,
}) })
} }
@ -1279,6 +1280,7 @@ pub fn data() -> Rc<Type> {
name: DATA.to_string(), name: DATA.to_string(),
module: "".to_string(), module: "".to_string(),
args: vec![], args: vec![],
alias: None,
}) })
} }
@ -1288,6 +1290,7 @@ pub fn byte_array() -> Rc<Type> {
public: true, public: true,
name: BYTE_ARRAY.to_string(), name: BYTE_ARRAY.to_string(),
module: "".to_string(), module: "".to_string(),
alias: None,
}) })
} }
@ -1297,6 +1300,7 @@ pub fn g1_element() -> Rc<Type> {
module: "".to_string(), module: "".to_string(),
name: G1_ELEMENT.to_string(), name: G1_ELEMENT.to_string(),
args: vec![], args: vec![],
alias: None,
}) })
} }
@ -1306,6 +1310,7 @@ pub fn g2_element() -> Rc<Type> {
module: "".to_string(), module: "".to_string(),
name: G2_ELEMENT.to_string(), name: G2_ELEMENT.to_string(),
args: vec![], args: vec![],
alias: None,
}) })
} }
@ -1315,11 +1320,12 @@ pub fn miller_loop_result() -> Rc<Type> {
module: "".to_string(), module: "".to_string(),
name: MILLER_LOOP_RESULT.to_string(), name: MILLER_LOOP_RESULT.to_string(),
args: vec![], args: vec![],
alias: None,
}) })
} }
pub fn tuple(elems: Vec<Rc<Type>>) -> Rc<Type> { pub fn tuple(elems: Vec<Rc<Type>>) -> Rc<Type> {
Rc::new(Type::Tuple { elems }) Rc::new(Type::Tuple { elems, alias: None })
} }
pub fn bool() -> Rc<Type> { pub fn bool() -> Rc<Type> {
@ -1328,6 +1334,7 @@ pub fn bool() -> Rc<Type> {
public: true, public: true,
name: BOOL.to_string(), name: BOOL.to_string(),
module: "".to_string(), module: "".to_string(),
alias: None,
}) })
} }
@ -1337,6 +1344,7 @@ pub fn prng() -> Rc<Type> {
public: true, public: true,
name: PRNG.to_string(), name: PRNG.to_string(),
module: "".to_string(), module: "".to_string(),
alias: None,
}) })
} }
@ -1344,6 +1352,7 @@ pub fn fuzzer(a: Rc<Type>) -> Rc<Type> {
Rc::new(Type::Fn { Rc::new(Type::Fn {
args: vec![prng()], args: vec![prng()],
ret: option(tuple(vec![prng(), a])), ret: option(tuple(vec![prng(), a])),
alias: Some(("Fuzzer".to_string(), vec!["a".to_string()])),
}) })
} }
@ -1353,6 +1362,7 @@ pub fn list(t: Rc<Type>) -> Rc<Type> {
name: LIST.to_string(), name: LIST.to_string(),
module: "".to_string(), module: "".to_string(),
args: vec![t], args: vec![t],
alias: None,
}) })
} }
@ -1362,6 +1372,7 @@ pub fn string() -> Rc<Type> {
public: true, public: true,
name: STRING.to_string(), name: STRING.to_string(),
module: "".to_string(), module: "".to_string(),
alias: None,
}) })
} }
@ -1371,6 +1382,7 @@ pub fn void() -> Rc<Type> {
public: true, public: true,
name: VOID.to_string(), name: VOID.to_string(),
module: "".to_string(), module: "".to_string(),
alias: None,
}) })
} }
@ -1380,6 +1392,7 @@ pub fn option(a: Rc<Type>) -> Rc<Type> {
name: OPTION.to_string(), name: OPTION.to_string(),
module: "".to_string(), module: "".to_string(),
args: vec![a], args: vec![a],
alias: None,
}) })
} }
@ -1389,23 +1402,26 @@ pub fn ordering() -> Rc<Type> {
name: ORDERING.to_string(), name: ORDERING.to_string(),
module: "".to_string(), module: "".to_string(),
args: vec![], args: vec![],
alias: None,
}) })
} }
pub fn function(args: Vec<Rc<Type>>, ret: Rc<Type>) -> Rc<Type> { pub fn function(args: Vec<Rc<Type>>, ret: Rc<Type>) -> Rc<Type> {
Rc::new(Type::Fn { ret, args }) Rc::new(Type::Fn {
ret,
args,
alias: None,
})
} }
pub fn generic_var(id: u64) -> Rc<Type> { pub fn generic_var(id: u64) -> Rc<Type> {
let tipo = Rc::new(RefCell::new(TypeVar::Generic { id })); let tipo = Rc::new(RefCell::new(TypeVar::Generic { id }));
Rc::new(Type::Var { tipo, alias: None })
Rc::new(Type::Var { tipo })
} }
pub fn unbound_var(id: u64) -> Rc<Type> { pub fn unbound_var(id: u64) -> Rc<Type> {
let tipo = Rc::new(RefCell::new(TypeVar::Unbound { id })); let tipo = Rc::new(RefCell::new(TypeVar::Unbound { id }));
Rc::new(Type::Var { tipo, alias: None })
Rc::new(Type::Var { tipo })
} }
pub fn wrapped_redeemer(redeemer: Rc<Type>) -> Rc<Type> { pub fn wrapped_redeemer(redeemer: Rc<Type>) -> Rc<Type> {
@ -1414,5 +1430,6 @@ pub fn wrapped_redeemer(redeemer: Rc<Type>) -> Rc<Type> {
module: "".to_string(), module: "".to_string(),
name: REDEEMER_WRAPPER.to_string(), name: REDEEMER_WRAPPER.to_string(),
args: vec![redeemer], args: vec![redeemer],
alias: None,
}) })
} }

View File

@ -626,7 +626,7 @@ impl UntypedExpr {
&Type, &Type,
) -> Result<Self, String>, ) -> Result<Self, String>,
{ {
if let Type::Var { tipo: var_tipo } = tipo { if let Type::Var { tipo: var_tipo, .. } = tipo {
match &*var_tipo.borrow() { match &*var_tipo.borrow() {
TypeVar::Link { tipo } => { TypeVar::Link { tipo } => {
return Self::reify_with(generics, data_types, t, tipo, with); return Self::reify_with(generics, data_types, t, tipo, with);
@ -724,7 +724,7 @@ impl UntypedExpr {
) )
} }
} }
Type::Tuple { elems } => Ok(UntypedExpr::Tuple { Type::Tuple { elems, .. } => Ok(UntypedExpr::Tuple {
location: Span::empty(), location: Span::empty(),
elems: args elems: args
.into_iter() .into_iter()
@ -740,7 +740,7 @@ impl UntypedExpr {
}, },
uplc::ast::Constant::ProtoPair(_, _, left, right) => match tipo { uplc::ast::Constant::ProtoPair(_, _, left, right) => match tipo {
Type::Tuple { elems } => Ok(UntypedExpr::Tuple { Type::Tuple { elems, .. } => Ok(UntypedExpr::Tuple {
location: Span::empty(), location: Span::empty(),
elems: [left.as_ref(), right.as_ref()] elems: [left.as_ref(), right.as_ref()]
.into_iter() .into_iter()
@ -959,7 +959,7 @@ impl UntypedExpr {
) )
} }
} }
Type::Tuple { elems } => Ok(UntypedExpr::Tuple { Type::Tuple { elems, .. } => Ok(UntypedExpr::Tuple {
location: Span::empty(), location: Span::empty(),
elems: args elems: args
.into_iter() .into_iter()

View File

@ -1,15 +1,13 @@
use indexmap::IndexSet; use super::air::{Air, ExpectLevel};
use itertools::Itertools;
use std::{borrow::BorrowMut, rc::Rc, slice::Iter};
use uplc::{builder::EXPECT_ON_LIST, builtins::DefaultFunction};
use crate::{ use crate::{
ast::{BinOp, Curve, Span, UnOp}, ast::{BinOp, Curve, Span, UnOp},
builtins::{bool, byte_array, data, int, list, string, void}, builtins::{bool, byte_array, data, int, list, string, void},
tipo::{Type, ValueConstructor, ValueConstructorVariant}, tipo::{Type, ValueConstructor, ValueConstructorVariant},
}; };
use indexmap::IndexSet;
use super::air::{Air, ExpectLevel}; use itertools::Itertools;
use std::{borrow::BorrowMut, rc::Rc, slice::Iter};
use uplc::{builder::EXPECT_ON_LIST, builtins::DefaultFunction};
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct TreePath { pub struct TreePath {
@ -720,6 +718,7 @@ impl AirTree {
Type::Fn { Type::Fn {
args: vec![list(data())], args: vec![list(data())],
ret: data(), ret: data(),
alias: None,
} }
.into(), .into(),
ValueConstructorVariant::ModuleFn { ValueConstructorVariant::ModuleFn {

View File

@ -23,7 +23,7 @@ mod pattern;
mod pipe; mod pipe;
pub mod pretty; pub mod pretty;
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone)]
pub enum Type { pub enum Type {
/// A nominal (named) type such as `Int`, `Float`, or a programmer defined /// A nominal (named) type such as `Int`, `Float`, or a programmer defined
/// custom type such as `Person`. The type can take other types as /// custom type such as `Person`. The type can take other types as
@ -38,6 +38,7 @@ pub enum Type {
module: String, module: String,
name: String, name: String,
args: Vec<Rc<Type>>, args: Vec<Rc<Type>>,
alias: Option<(String, Vec<String>)>,
}, },
/// The type of a function. It takes arguments and returns a value. /// The type of a function. It takes arguments and returns a value.
@ -45,12 +46,14 @@ pub enum Type {
Fn { Fn {
args: Vec<Rc<Type>>, args: Vec<Rc<Type>>,
ret: Rc<Type>, ret: Rc<Type>,
alias: Option<(String, Vec<String>)>,
}, },
/// A type variable. See the contained `TypeVar` enum for more information. /// A type variable. See the contained `TypeVar` enum for more information.
/// ///
Var { Var {
tipo: Rc<RefCell<TypeVar>>, tipo: Rc<RefCell<TypeVar>>,
alias: Option<(String, Vec<String>)>,
}, },
// /// A tuple is an ordered collection of 0 or more values, each of which // /// A tuple is an ordered collection of 0 or more values, each of which
// /// can have a different type, so the `tuple` type is the sum of all the // /// can have a different type, so the `tuple` type is the sum of all the
@ -58,15 +61,104 @@ pub enum Type {
// /// // ///
Tuple { Tuple {
elems: Vec<Rc<Type>>, elems: Vec<Rc<Type>>,
alias: Option<(String, Vec<String>)>,
}, },
} }
impl PartialEq for Type {
fn eq(&self, other: &Type) -> bool {
match self {
Type::App {
public,
module,
name,
args,
..
} => {
if let Type::App {
public: public2,
module: module2,
name: name2,
args: args2,
..
} = other
{
name == name2
&& module == module2
&& public == public2
&& args.iter().zip(args2).all(|(left, right)| left == right)
} else {
false
}
}
Type::Fn { args, ret, .. } => {
if let Type::Fn {
args: args2,
ret: ret2,
..
} = other
{
ret == ret2 && args.iter().zip(args2).all(|(left, right)| left == right)
} else {
false
}
}
Type::Tuple { elems, .. } => {
if let Type::Tuple { elems: elems2, .. } = other {
elems.iter().zip(elems2).all(|(left, right)| left == right)
} else {
false
}
}
Type::Var { tipo, .. } => {
if let Type::Var { tipo: tipo2, .. } = other {
tipo == tipo2
} else {
false
}
}
}
}
}
impl Type { impl Type {
pub fn with_alias(tipo: Rc<Type>, alias: &Option<(String, Vec<String>)>) -> Rc<Type> {
match alias {
None => tipo,
Some((name, args)) => tipo.as_ref().to_owned().set_alias(name, args),
}
}
pub fn set_alias(self, name: &str, args: &[String]) -> Rc<Type> {
let alias = Some((name.to_string(), args.to_vec()));
Rc::new(match self {
Type::App {
public,
module,
name,
args,
..
} => Type::App {
public,
module,
name,
args,
alias,
},
Type::Fn { args, ret, .. } => Type::Fn { args, ret, alias },
Type::Var { tipo, .. } => Type::Var { tipo, alias },
Type::Tuple { elems, .. } => Type::Tuple { elems, alias },
})
}
pub fn qualifier(&self) -> Option<(String, String)> { pub fn qualifier(&self) -> Option<(String, String)> {
match self { match self {
Type::App { module, name, .. } => Some((module.to_string(), name.to_string())), Type::App { module, name, .. } => Some((module.to_string(), name.to_string())),
Type::Fn { .. } => None, Type::Fn { .. } => None,
Type::Var { ref tipo } => match &*tipo.borrow() { Type::Var { ref tipo, .. } => match &*tipo.borrow() {
TypeVar::Link { ref tipo } => tipo.qualifier(), TypeVar::Link { ref tipo } => tipo.qualifier(),
_ => None, _ => None,
}, },
@ -86,7 +178,7 @@ impl Type {
} }
pub fn is_unbound(&self) -> bool { pub fn is_unbound(&self) -> bool {
matches!(self, Self::Var { tipo } if tipo.borrow().is_unbound()) matches!(self, Self::Var { tipo, .. } if tipo.borrow().is_unbound())
} }
pub fn is_function(&self) -> bool { pub fn is_function(&self) -> bool {
@ -119,7 +211,7 @@ impl Type {
pub fn is_void(&self) -> bool { pub fn is_void(&self) -> bool {
match self { match self {
Self::App { module, name, .. } if "Void" == name && module.is_empty() => true, Self::App { module, name, .. } if "Void" == name && module.is_empty() => true,
Self::Var { tipo } => tipo.borrow().is_void(), Self::Var { tipo, .. } => tipo.borrow().is_void(),
_ => false, _ => false,
} }
} }
@ -127,7 +219,7 @@ impl Type {
pub fn is_bool(&self) -> bool { pub fn is_bool(&self) -> bool {
match self { match self {
Self::App { module, name, .. } if "Bool" == name && module.is_empty() => true, Self::App { module, name, .. } if "Bool" == name && module.is_empty() => true,
Self::Var { tipo } => tipo.borrow().is_bool(), Self::Var { tipo, .. } => tipo.borrow().is_bool(),
_ => false, _ => false,
} }
} }
@ -135,7 +227,7 @@ impl Type {
pub fn is_int(&self) -> bool { pub fn is_int(&self) -> bool {
match self { match self {
Self::App { module, name, .. } if "Int" == name && module.is_empty() => true, Self::App { module, name, .. } if "Int" == name && module.is_empty() => true,
Self::Var { tipo } => tipo.borrow().is_int(), Self::Var { tipo, .. } => tipo.borrow().is_int(),
_ => false, _ => false,
} }
} }
@ -143,7 +235,7 @@ impl Type {
pub fn is_bytearray(&self) -> bool { pub fn is_bytearray(&self) -> bool {
match self { match self {
Self::App { module, name, .. } if "ByteArray" == name && module.is_empty() => true, Self::App { module, name, .. } if "ByteArray" == name && module.is_empty() => true,
Self::Var { tipo } => tipo.borrow().is_bytearray(), Self::Var { tipo, .. } => tipo.borrow().is_bytearray(),
_ => false, _ => false,
} }
} }
@ -152,7 +244,7 @@ impl Type {
match self { match self {
Self::App { module, name, .. } => G1_ELEMENT == name && module.is_empty(), Self::App { module, name, .. } => G1_ELEMENT == name && module.is_empty(),
Self::Var { tipo } => tipo.borrow().is_bls381_12_g1(), Self::Var { tipo, .. } => tipo.borrow().is_bls381_12_g1(),
_ => false, _ => false,
} }
} }
@ -161,7 +253,7 @@ impl Type {
match self { match self {
Self::App { module, name, .. } => G2_ELEMENT == name && module.is_empty(), Self::App { module, name, .. } => G2_ELEMENT == name && module.is_empty(),
Self::Var { tipo } => tipo.borrow().is_bls381_12_g2(), Self::Var { tipo, .. } => tipo.borrow().is_bls381_12_g2(),
_ => false, _ => false,
} }
} }
@ -170,7 +262,7 @@ impl Type {
match self { match self {
Self::App { module, name, .. } => MILLER_LOOP_RESULT == name && module.is_empty(), Self::App { module, name, .. } => MILLER_LOOP_RESULT == name && module.is_empty(),
Self::Var { tipo } => tipo.borrow().is_ml_result(), Self::Var { tipo, .. } => tipo.borrow().is_ml_result(),
_ => false, _ => false,
} }
} }
@ -178,7 +270,7 @@ impl Type {
pub fn is_string(&self) -> bool { pub fn is_string(&self) -> bool {
match self { match self {
Self::App { module, name, .. } if "String" == name && module.is_empty() => true, Self::App { module, name, .. } if "String" == name && module.is_empty() => true,
Self::Var { tipo } => tipo.borrow().is_string(), Self::Var { tipo, .. } => tipo.borrow().is_string(),
_ => false, _ => false,
} }
} }
@ -186,7 +278,7 @@ impl Type {
pub fn is_list(&self) -> bool { pub fn is_list(&self) -> bool {
match self { match self {
Self::App { module, name, .. } if "List" == name && module.is_empty() => true, Self::App { module, name, .. } if "List" == name && module.is_empty() => true,
Self::Var { tipo } => tipo.borrow().is_list(), Self::Var { tipo, .. } => tipo.borrow().is_list(),
_ => false, _ => false,
} }
} }
@ -194,7 +286,7 @@ impl Type {
pub fn is_option(&self) -> bool { pub fn is_option(&self) -> bool {
match self { match self {
Self::App { module, name, .. } if "Option" == name && module.is_empty() => true, Self::App { module, name, .. } if "Option" == name && module.is_empty() => true,
Self::Var { tipo } => tipo.borrow().is_option(), Self::Var { tipo, .. } => tipo.borrow().is_option(),
_ => false, _ => false,
} }
} }
@ -207,14 +299,14 @@ impl Type {
.first() .first()
.expect("unreachable: List should have an inner type") .expect("unreachable: List should have an inner type")
.is_2_tuple(), .is_2_tuple(),
Self::Var { tipo } => tipo.borrow().is_map(), Self::Var { tipo, .. } => tipo.borrow().is_map(),
_ => false, _ => false,
} }
} }
pub fn is_tuple(&self) -> bool { pub fn is_tuple(&self) -> bool {
match self { match self {
Type::Var { tipo } => tipo.borrow().is_tuple(), Type::Var { tipo, .. } => tipo.borrow().is_tuple(),
Type::Tuple { .. } => true, Type::Tuple { .. } => true,
_ => false, _ => false,
} }
@ -222,8 +314,8 @@ impl Type {
pub fn is_2_tuple(&self) -> bool { pub fn is_2_tuple(&self) -> bool {
match self { match self {
Type::Var { tipo } => tipo.borrow().is_2_tuple(), Type::Var { tipo, .. } => tipo.borrow().is_2_tuple(),
Type::Tuple { elems } => elems.len() == 2, Type::Tuple { elems, .. } => elems.len() == 2,
_ => false, _ => false,
} }
} }
@ -231,7 +323,7 @@ impl Type {
pub fn is_data(&self) -> bool { pub fn is_data(&self) -> bool {
match self { match self {
Self::App { module, name, .. } => "Data" == name && module.is_empty(), Self::App { module, name, .. } => "Data" == name && module.is_empty(),
Self::Var { tipo } => tipo.borrow().is_data(), Self::Var { tipo, .. } => tipo.borrow().is_data(),
_ => false, _ => false,
} }
} }
@ -246,15 +338,15 @@ impl Type {
is_a_generic is_a_generic
} }
Type::Var { tipo } => tipo.borrow().is_generic(), Type::Var { tipo, .. } => tipo.borrow().is_generic(),
Type::Tuple { elems } => { Type::Tuple { elems, .. } => {
let mut is_a_generic = false; let mut is_a_generic = false;
for elem in elems { for elem in elems {
is_a_generic = is_a_generic || elem.is_generic(); is_a_generic = is_a_generic || elem.is_generic();
} }
is_a_generic is_a_generic
} }
Type::Fn { args, ret } => { Type::Fn { args, ret, .. } => {
let mut is_a_generic = false; let mut is_a_generic = false;
for arg in args { for arg in args {
is_a_generic = is_a_generic || arg.is_generic(); is_a_generic = is_a_generic || arg.is_generic();
@ -268,14 +360,14 @@ impl Type {
match self { match self {
Self::Fn { args, .. } => Some(args.clone()), Self::Fn { args, .. } => Some(args.clone()),
Self::App { args, .. } => Some(args.clone()), Self::App { args, .. } => Some(args.clone()),
Self::Var { tipo } => tipo.borrow().arg_types(), Self::Var { tipo, .. } => tipo.borrow().arg_types(),
_ => None, _ => None,
} }
} }
pub fn get_generic(&self) -> Option<u64> { pub fn get_generic(&self) -> Option<u64> {
match self { match self {
Type::Var { tipo } => tipo.borrow().get_generic(), Type::Var { tipo, .. } => tipo.borrow().get_generic(),
_ => None, _ => None,
} }
} }
@ -284,24 +376,24 @@ impl Type {
if self.is_list() { if self.is_list() {
match self { match self {
Self::App { args, .. } => args.clone(), Self::App { args, .. } => args.clone(),
Self::Var { tipo } => tipo.borrow().get_inner_types(), Self::Var { tipo, .. } => tipo.borrow().get_inner_types(),
_ => vec![], _ => vec![],
} }
} else if self.is_tuple() { } else if self.is_tuple() {
match self { match self {
Self::Tuple { elems } => elems.to_vec(), Self::Tuple { elems, .. } => elems.to_vec(),
Self::Var { tipo } => tipo.borrow().get_inner_types(), Self::Var { tipo, .. } => tipo.borrow().get_inner_types(),
_ => vec![], _ => vec![],
} }
} else if matches!(self.get_uplc_type(), UplcType::Data) { } else if matches!(self.get_uplc_type(), UplcType::Data) {
match self { match self {
Type::App { args, .. } => args.clone(), Type::App { args, .. } => args.clone(),
Type::Fn { args, ret } => { Type::Fn { args, ret, .. } => {
let mut args = args.clone(); let mut args = args.clone();
args.push(ret.clone()); args.push(ret.clone());
args args
} }
Type::Var { tipo } => tipo.borrow().get_inner_types(), Type::Var { tipo, .. } => tipo.borrow().get_inner_types(),
_ => unreachable!(), _ => unreachable!(),
} }
} else { } else {
@ -324,14 +416,14 @@ impl Type {
UplcType::List(UplcType::Data.into()) UplcType::List(UplcType::Data.into())
} else if self.is_tuple() { } else if self.is_tuple() {
match self { match self {
Self::Tuple { elems } => { Self::Tuple { elems, .. } => {
if elems.len() == 2 { if elems.len() == 2 {
UplcType::Pair(UplcType::Data.into(), UplcType::Data.into()) UplcType::Pair(UplcType::Data.into(), UplcType::Data.into())
} else { } else {
UplcType::List(UplcType::Data.into()) UplcType::List(UplcType::Data.into())
} }
} }
Self::Var { tipo } => tipo.borrow().get_uplc_type().unwrap(), Self::Var { tipo, .. } => tipo.borrow().get_uplc_type().unwrap(),
_ => unreachable!(), _ => unreachable!(),
} }
} else if self.is_bls381_12_g1() { } else if self.is_bls381_12_g1() {
@ -371,7 +463,7 @@ impl Type {
} }
} }
Self::Var { tipo } => { Self::Var { tipo, alias } => {
let args: Vec<_> = match tipo.borrow().deref() { let args: Vec<_> = match tipo.borrow().deref() {
TypeVar::Link { tipo } => { TypeVar::Link { tipo } => {
return tipo.get_app_args(public, module, name, arity, environment); return tipo.get_app_args(public, module, name, arity, environment);
@ -388,10 +480,11 @@ impl Type {
// to the desired type. // to the desired type.
*tipo.borrow_mut() = TypeVar::Link { *tipo.borrow_mut() = TypeVar::Link {
tipo: Rc::new(Self::App { tipo: Rc::new(Self::App {
public,
name: name.to_string(), name: name.to_string(),
module: module.to_owned(), module: module.to_owned(),
args: args.clone(), args: args.clone(),
public, alias: alias.to_owned(),
}), }),
}; };
Some(args) Some(args)
@ -465,7 +558,7 @@ pub fn lookup_data_type_by_tipo(
data_types.get(&data_type_key).map(|item| (*item).clone()) data_types.get(&data_type_key).map(|item| (*item).clone())
} }
Type::Var { tipo } => { Type::Var { tipo, .. } => {
if let TypeVar::Link { tipo } = &*tipo.borrow() { if let TypeVar::Link { tipo } = &*tipo.borrow() {
lookup_data_type_by_tipo(data_types, tipo) lookup_data_type_by_tipo(data_types, tipo)
} else { } else {
@ -500,11 +593,11 @@ pub fn get_arg_type_name(tipo: &Type) -> String {
let inner_args = args.iter().map(|arg| get_arg_type_name(arg)).collect_vec(); let inner_args = args.iter().map(|arg| get_arg_type_name(arg)).collect_vec();
format!("{}_{}", name, inner_args.join("_")) format!("{}_{}", name, inner_args.join("_"))
} }
Type::Var { tipo } => match tipo.borrow().clone() { Type::Var { tipo, .. } => match tipo.borrow().clone() {
TypeVar::Link { tipo } => get_arg_type_name(tipo.as_ref()), TypeVar::Link { tipo } => get_arg_type_name(tipo.as_ref()),
_ => unreachable!(), _ => unreachable!(),
}, },
Type::Tuple { elems } => { Type::Tuple { elems, .. } => {
let inner_args = elems.iter().map(|arg| get_arg_type_name(arg)).collect_vec(); let inner_args = elems.iter().map(|arg| get_arg_type_name(arg)).collect_vec();
inner_args.join("_") inner_args.join("_")
} }
@ -545,6 +638,7 @@ pub fn convert_opaque_type(
module, module,
name, name,
args, args,
alias,
} => { } => {
let mut new_args = vec![]; let mut new_args = vec![];
for arg in args { for arg in args {
@ -556,10 +650,11 @@ pub fn convert_opaque_type(
module: module.clone(), module: module.clone(),
name: name.clone(), name: name.clone(),
args: new_args, args: new_args,
alias: alias.clone(),
} }
.into() .into()
} }
Type::Fn { args, ret } => { Type::Fn { args, ret, alias } => {
let mut new_args = vec![]; let mut new_args = vec![];
for arg in args { for arg in args {
let arg = convert_opaque_type(arg, data_types, deep); let arg = convert_opaque_type(arg, data_types, deep);
@ -571,23 +666,28 @@ pub fn convert_opaque_type(
Type::Fn { Type::Fn {
args: new_args, args: new_args,
ret, ret,
alias: alias.clone(),
} }
.into() .into()
} }
Type::Var { tipo: var_tipo } => { Type::Var { tipo: var_tipo, .. } => {
if let TypeVar::Link { tipo } = &var_tipo.borrow().clone() { if let TypeVar::Link { tipo } = &var_tipo.borrow().clone() {
convert_opaque_type(tipo, data_types, deep) convert_opaque_type(tipo, data_types, deep)
} else { } else {
t.clone() t.clone()
} }
} }
Type::Tuple { elems } => { Type::Tuple { elems, alias } => {
let mut new_elems = vec![]; let mut new_elems = vec![];
for arg in elems { for arg in elems {
let arg = convert_opaque_type(arg, data_types, deep); let arg = convert_opaque_type(arg, data_types, deep);
new_elems.push(arg); new_elems.push(arg);
} }
Type::Tuple { elems: new_elems }.into() Type::Tuple {
elems: new_elems,
alias: alias.clone(),
}
.into()
} }
} }
} }
@ -623,6 +723,7 @@ pub fn find_and_replace_generics(
public, public,
module, module,
name, name,
alias,
} => { } => {
let mut new_args = vec![]; let mut new_args = vec![];
for arg in args { for arg in args {
@ -634,10 +735,11 @@ pub fn find_and_replace_generics(
public: *public, public: *public,
module: module.clone(), module: module.clone(),
name: name.clone(), name: name.clone(),
alias: alias.clone(),
}; };
t.into() t.into()
} }
Type::Fn { args, ret } => { Type::Fn { args, ret, alias } => {
let mut new_args = vec![]; let mut new_args = vec![];
for arg in args { for arg in args {
let arg = find_and_replace_generics(arg, mono_types); let arg = find_and_replace_generics(arg, mono_types);
@ -649,20 +751,24 @@ pub fn find_and_replace_generics(
let t = Type::Fn { let t = Type::Fn {
args: new_args, args: new_args,
ret, ret,
alias: alias.clone(),
}; };
t.into() t.into()
} }
Type::Tuple { elems } => { Type::Tuple { elems, alias } => {
let mut new_elems = vec![]; let mut new_elems = vec![];
for elem in elems { for elem in elems {
let elem = find_and_replace_generics(elem, mono_types); let elem = find_and_replace_generics(elem, mono_types);
new_elems.push(elem); new_elems.push(elem);
} }
let t = Type::Tuple { elems: new_elems }; let t = Type::Tuple {
elems: new_elems,
alias: alias.clone(),
};
t.into() t.into()
} }
Type::Var { tipo: var_tipo } => { Type::Var { tipo: var_tipo, .. } => {
let var_type = var_tipo.as_ref().borrow().clone(); let var_type = var_tipo.as_ref().borrow().clone();
match var_type { match var_type {
@ -833,10 +939,13 @@ impl TypeVar {
Self::Link { tipo } => tipo.get_inner_types(), Self::Link { tipo } => tipo.get_inner_types(),
Self::Unbound { .. } => vec![], Self::Unbound { .. } => vec![],
var => { var => {
vec![Type::Var { vec![
Type::Var {
tipo: RefCell::new(var.clone()).into(), tipo: RefCell::new(var.clone()).into(),
alias: None,
} }
.into()] .into(),
]
} }
} }
} }

View File

@ -1,9 +1,10 @@
use std::{ use super::{
collections::{HashMap, HashSet}, error::{Error, Snippet, Warning},
ops::Deref, exhaustive::{simplify, Matrix, PatternStack},
rc::Rc, hydrator::Hydrator,
AccessorsMap, RecordAccessor, Type, TypeConstructor, TypeInfo, TypeVar, ValueConstructor,
ValueConstructorVariant,
}; };
use crate::{ use crate::{
ast::{ ast::{
Annotation, CallArg, DataType, Definition, Function, ModuleConstant, ModuleKind, Annotation, CallArg, DataType, Definition, Function, ModuleConstant, ModuleKind,
@ -14,13 +15,10 @@ use crate::{
tipo::fields::FieldMap, tipo::fields::FieldMap,
IdGenerator, IdGenerator,
}; };
use std::{
use super::{ collections::{HashMap, HashSet},
error::{Error, Snippet, Warning}, ops::Deref,
exhaustive::{simplify, Matrix, PatternStack}, rc::Rc,
hydrator::Hydrator,
AccessorsMap, RecordAccessor, Type, TypeConstructor, TypeInfo, TypeVar, ValueConstructor,
ValueConstructorVariant,
}; };
#[derive(Debug)] #[derive(Debug)]
@ -119,7 +117,7 @@ impl<'a> Environment<'a> {
fn_location: Span, fn_location: Span,
call_location: Span, call_location: Span,
) -> Result<(Vec<Rc<Type>>, Rc<Type>), Error> { ) -> Result<(Vec<Rc<Type>>, Rc<Type>), Error> {
if let Type::Var { tipo } = tipo.deref() { if let Type::Var { tipo, .. } = tipo.deref() {
let new_value = match tipo.borrow().deref() { let new_value = match tipo.borrow().deref() {
TypeVar::Link { tipo, .. } => { TypeVar::Link { tipo, .. } => {
return self.match_fun_type(tipo.clone(), arity, fn_location, call_location); return self.match_fun_type(tipo.clone(), arity, fn_location, call_location);
@ -145,7 +143,7 @@ impl<'a> Environment<'a> {
} }
} }
if let Type::Fn { args, ret } = tipo.deref() { if let Type::Fn { args, ret, .. } = tipo.deref() {
return if args.len() != arity { return if args.len() != arity {
Err(Error::IncorrectFunctionCallArity { Err(Error::IncorrectFunctionCallArity {
expected: args.len(), expected: args.len(),
@ -549,6 +547,7 @@ impl<'a> Environment<'a> {
name, name,
module, module,
args, args,
alias,
} => { } => {
let args = args let args = args
.iter() .iter()
@ -558,15 +557,26 @@ impl<'a> Environment<'a> {
public: *public, public: *public,
name: name.clone(), name: name.clone(),
module: module.clone(), module: module.clone(),
alias: alias.clone(),
args, args,
}) })
} }
Type::Var { tipo } => { Type::Var { tipo, alias } => {
match tipo.borrow().deref() { match tipo.borrow().deref() {
TypeVar::Link { tipo } => return self.instantiate(tipo.clone(), ids, hydrator), TypeVar::Link { tipo } => {
return Type::with_alias(
self.instantiate(tipo.clone(), ids, hydrator),
alias,
);
}
TypeVar::Unbound { .. } => return Rc::new(Type::Var { tipo: tipo.clone() }), TypeVar::Unbound { .. } => {
return Rc::new(Type::Var {
tipo: tipo.clone(),
alias: alias.clone(),
});
}
TypeVar::Generic { id } => match ids.get(id) { TypeVar::Generic { id } => match ids.get(id) {
Some(t) => return t.clone(), Some(t) => return t.clone(),
@ -576,28 +586,35 @@ impl<'a> Environment<'a> {
let v = self.new_unbound_var(); let v = self.new_unbound_var();
ids.insert(*id, v.clone()); ids.insert(*id, v.clone());
return v; return v;
} else {
// tracing::trace!(id = id, "not_instantiating_rigid_type_var")
} }
} }
}, },
} }
Rc::new(Type::Var { tipo: tipo.clone() }) Rc::new(Type::Var {
tipo: tipo.clone(),
alias: alias.clone(),
})
} }
Type::Fn { args, ret, .. } => function( Type::Fn { args, ret, alias } => Type::with_alias(
function(
args.iter() args.iter()
.map(|t| self.instantiate(t.clone(), ids, hydrator)) .map(|t| self.instantiate(t.clone(), ids, hydrator))
.collect(), .collect(),
self.instantiate(ret.clone(), ids, hydrator), self.instantiate(ret.clone(), ids, hydrator),
), ),
alias,
),
Type::Tuple { elems } => tuple( Type::Tuple { elems, alias } => Type::with_alias(
tuple(
elems elems
.iter() .iter()
.map(|t| self.instantiate(t.clone(), ids, hydrator)) .map(|t| self.instantiate(t.clone(), ids, hydrator))
.collect(), .collect(),
), ),
alias,
),
} }
} }
@ -981,6 +998,7 @@ impl<'a> Environment<'a> {
module: module.to_owned(), module: module.to_owned(),
name: name.clone(), name: name.clone(),
args: parameters.clone(), args: parameters.clone(),
alias: None,
}); });
hydrators.insert(name.to_string(), hydrator); hydrators.insert(name.to_string(), hydrator);
@ -1024,7 +1042,11 @@ impl<'a> Environment<'a> {
hydrator.disallow_new_type_variables(); hydrator.disallow_new_type_variables();
// Create the type that the alias resolves to // Create the type that the alias resolves to
let tipo = hydrator.type_from_annotation(resolved_type, self)?; let tipo = hydrator
.type_from_annotation(resolved_type, self)?
.as_ref()
.to_owned()
.set_alias(name, args);
self.insert_type_constructor( self.insert_type_constructor(
name.clone(), name.clone(),
@ -1353,13 +1375,13 @@ impl<'a> Environment<'a> {
} }
// Collapse right hand side type links. Left hand side will be collapsed in the next block. // Collapse right hand side type links. Left hand side will be collapsed in the next block.
if let Type::Var { tipo } = t2.deref() { if let Type::Var { tipo, .. } = t2.deref() {
if let TypeVar::Link { tipo } = tipo.borrow().deref() { if let TypeVar::Link { tipo, .. } = tipo.borrow().deref() {
return self.unify(t1, tipo.clone(), location, allow_cast); return self.unify(t1, tipo.clone(), location, allow_cast);
} }
} }
if let Type::Var { tipo } = t1.deref() { if let Type::Var { tipo, .. } = t1.deref() {
enum Action { enum Action {
Unify(Rc<Type>), Unify(Rc<Type>),
CouldNotUnify, CouldNotUnify,
@ -1375,7 +1397,7 @@ impl<'a> Environment<'a> {
} }
TypeVar::Generic { id } => { TypeVar::Generic { id } => {
if let Type::Var { tipo } = t2.deref() { if let Type::Var { tipo, .. } = t2.deref() {
if tipo.borrow().is_unbound() { if tipo.borrow().is_unbound() {
*tipo.borrow_mut() = TypeVar::Generic { id: *id }; *tipo.borrow_mut() = TypeVar::Generic { id: *id };
return Ok(()); return Ok(());
@ -1642,10 +1664,10 @@ pub enum EntityKind {
/// could cause naively-implemented type checking to diverge. /// could cause naively-implemented type checking to diverge.
/// While traversing the type tree. /// While traversing the type tree.
fn unify_unbound_type(tipo: Rc<Type>, own_id: u64, location: Span) -> Result<(), Error> { fn unify_unbound_type(tipo: Rc<Type>, own_id: u64, location: Span) -> Result<(), Error> {
if let Type::Var { tipo } = tipo.deref() { if let Type::Var { tipo, .. } = tipo.deref() {
let new_value = match tipo.borrow().deref() { let new_value = match tipo.borrow().deref() {
TypeVar::Link { tipo, .. } => { TypeVar::Link { tipo, .. } => {
return unify_unbound_type(tipo.clone(), own_id, location) return unify_unbound_type(tipo.clone(), own_id, location);
} }
TypeVar::Unbound { id } => { TypeVar::Unbound { id } => {
@ -1674,7 +1696,7 @@ fn unify_unbound_type(tipo: Rc<Type>, own_id: u64, location: Span) -> Result<(),
Ok(()) Ok(())
} }
Type::Fn { args, ret } => { Type::Fn { args, ret, .. } => {
for arg in args { for arg in args {
unify_unbound_type(arg.clone(), own_id, location)?; unify_unbound_type(arg.clone(), own_id, location)?;
} }
@ -1769,7 +1791,7 @@ pub(super) fn assert_no_labeled_arguments<A>(args: &[CallArg<A>]) -> Option<(Spa
} }
pub(super) fn collapse_links(t: Rc<Type>) -> Rc<Type> { pub(super) fn collapse_links(t: Rc<Type>) -> Rc<Type> {
if let Type::Var { tipo } = t.deref() { if let Type::Var { tipo, .. } = t.deref() {
if let TypeVar::Link { tipo } = tipo.borrow().deref() { if let TypeVar::Link { tipo } = tipo.borrow().deref() {
return tipo.clone(); return tipo.clone();
} }
@ -1811,17 +1833,24 @@ fn get_compatible_record_fields<A>(
#[allow(clippy::only_used_in_recursion)] #[allow(clippy::only_used_in_recursion)]
pub(crate) fn generalise(t: Rc<Type>, ctx_level: usize) -> Rc<Type> { pub(crate) fn generalise(t: Rc<Type>, ctx_level: usize) -> Rc<Type> {
match t.deref() { match t.deref() {
Type::Var { tipo } => match tipo.borrow().deref() { Type::Var { tipo, alias } => Type::with_alias(
match tipo.borrow().deref() {
TypeVar::Unbound { id } => generic_var(*id), TypeVar::Unbound { id } => generic_var(*id),
TypeVar::Link { tipo } => generalise(tipo.clone(), ctx_level), TypeVar::Link { tipo } => generalise(tipo.clone(), ctx_level),
TypeVar::Generic { .. } => Rc::new(Type::Var { tipo: tipo.clone() }), TypeVar::Generic { .. } => Rc::new(Type::Var {
tipo: tipo.clone(),
alias: None,
}),
}, },
alias,
),
Type::App { Type::App {
public, public,
module, module,
name, name,
args, args,
alias,
} => { } => {
let args = args let args = args
.iter() .iter()
@ -1833,21 +1862,28 @@ pub(crate) fn generalise(t: Rc<Type>, ctx_level: usize) -> Rc<Type> {
module: module.clone(), module: module.clone(),
name: name.clone(), name: name.clone(),
args, args,
alias: alias.clone(),
}) })
} }
Type::Fn { args, ret } => function( Type::Fn { args, ret, alias } => Type::with_alias(
function(
args.iter() args.iter()
.map(|t| generalise(t.clone(), ctx_level)) .map(|t| generalise(t.clone(), ctx_level))
.collect(), .collect(),
generalise(ret.clone(), ctx_level), generalise(ret.clone(), ctx_level),
), ),
alias,
),
Type::Tuple { elems } => tuple( Type::Tuple { elems, alias } => Type::with_alias(
tuple(
elems elems
.iter() .iter()
.map(|t| generalise(t.clone(), ctx_level)) .map(|t| generalise(t.clone(), ctx_level))
.collect(), .collect(),
), ),
alias,
),
} }
} }

View File

@ -608,7 +608,7 @@ pub(super) fn simplify(
Ok(Pattern::Constructor( Ok(Pattern::Constructor(
TUPLE_NAME.to_string(), TUPLE_NAME.to_string(),
vec![tipo::ValueConstructor { vec![tipo::ValueConstructor {
tipo: tipo::Type::Tuple { elems: vec![] }.into(), tipo: tipo::Type::Tuple { elems: vec![], alias: None }.into(),
public: true, public: true,
variant: tipo::ValueConstructorVariant::Record { variant: tipo::ValueConstructorVariant::Record {
name: TUPLE_NAME.to_string(), name: TUPLE_NAME.to_string(),

View File

@ -1,16 +1,14 @@
use std::{collections::HashMap, rc::Rc};
use crate::{
ast::Annotation,
builtins::{function, tuple},
tipo::Span,
};
use super::{ use super::{
environment::Environment, environment::Environment,
error::{Error, Warning}, error::{Error, Warning},
Type, TypeConstructor, Type, TypeConstructor,
}; };
use crate::{
ast::Annotation,
builtins::{function, tuple},
tipo::Span,
};
use std::{collections::HashMap, rc::Rc};
/// The Hydrator takes an AST representing a type (i.e. a type annotation /// The Hydrator takes an AST representing a type (i.e. a type annotation
/// for a function argument) and returns a Type for that annotation. /// for a function argument) and returns a Type for that annotation.

View File

@ -382,10 +382,14 @@ fn infer_definition(
.scope .scope
.get_mut(&f.name) .get_mut(&f.name)
.expect("Could not find preregistered type for test"); .expect("Could not find preregistered type for test");
if let Type::Fn { ref ret, .. } = scope.tipo.as_ref() { if let Type::Fn {
ref ret, ref alias, ..
} = scope.tipo.as_ref()
{
scope.tipo = Rc::new(Type::Fn { scope.tipo = Rc::new(Type::Fn {
ret: ret.clone(), ret: ret.clone(),
args: vec![inferred_inner_type.clone()], args: vec![inferred_inner_type.clone()],
alias: alias.clone(),
}) })
} }
@ -782,7 +786,7 @@ fn infer_fuzzer(
module, name, args, .. module, name, args, ..
} if module.is_empty() && name == "Option" && args.len() == 1 => { } if module.is_empty() && name == "Option" && args.len() == 1 => {
match args.first().expect("args.len() == 1").borrow() { match args.first().expect("args.len() == 1").borrow() {
Type::Tuple { elems } if elems.len() == 2 => { Type::Tuple { elems, .. } if elems.len() == 2 => {
let wrapped = elems.get(1).expect("Tuple has two elements"); let wrapped = elems.get(1).expect("Tuple has two elements");
// NOTE: Although we've drilled through the Fuzzer structure to get here, // NOTE: Although we've drilled through the Fuzzer structure to get here,
@ -843,7 +847,7 @@ fn annotate_fuzzer(tipo: &Type, location: &Span) -> Result<Annotation, Error> {
}) })
} }
Type::Tuple { elems } => { Type::Tuple { elems, .. } => {
let elems = elems let elems = elems
.iter() .iter()
.map(|arg| annotate_fuzzer(arg, location)) .map(|arg| annotate_fuzzer(arg, location))
@ -854,7 +858,7 @@ fn annotate_fuzzer(tipo: &Type, location: &Span) -> Result<Annotation, Error> {
}) })
} }
Type::Var { tipo } => match &*tipo.deref().borrow() { Type::Var { tipo, .. } => match &*tipo.deref().borrow() {
TypeVar::Link { tipo } => annotate_fuzzer(tipo, location), TypeVar::Link { tipo } => annotate_fuzzer(tipo, location),
_ => Err(Error::GenericLeftAtBoundary { _ => Err(Error::GenericLeftAtBoundary {
location: *location, location: *location,

View File

@ -1,13 +1,5 @@
//! Type inference and checking of patterns used in case expressions //! Type inference and checking of patterns used in case expressions
//! and variables bindings. //! and variables bindings.
use std::{
collections::{HashMap, HashSet},
ops::Deref,
rc::Rc,
};
use itertools::Itertools;
use super::{ use super::{
environment::{assert_no_labeled_arguments, collapse_links, EntityKind, Environment}, environment::{assert_no_labeled_arguments, collapse_links, EntityKind, Environment},
error::{Error, Warning}, error::{Error, Warning},
@ -18,6 +10,12 @@ use crate::{
ast::{CallArg, Pattern, Span, TypedPattern, UntypedPattern}, ast::{CallArg, Pattern, Span, TypedPattern, UntypedPattern},
builtins::{int, list, tuple}, builtins::{int, list, tuple},
}; };
use itertools::Itertools;
use std::{
collections::{HashMap, HashSet},
ops::Deref,
rc::Rc,
};
pub struct PatternTyper<'a, 'b> { pub struct PatternTyper<'a, 'b> {
environment: &'a mut Environment<'b>, environment: &'a mut Environment<'b>,
@ -238,7 +236,9 @@ impl<'a, 'b> PatternTyper<'a, 'b> {
}, },
Pattern::Tuple { elems, location } => match collapse_links(tipo.clone()).deref() { Pattern::Tuple { elems, location } => match collapse_links(tipo.clone()).deref() {
Type::Tuple { elems: type_elems } => { Type::Tuple {
elems: type_elems, ..
} => {
if elems.len() != type_elems.len() { if elems.len() != type_elems.len() {
return Err(Error::IncorrectTupleArity { return Err(Error::IncorrectTupleArity {
location, location,
@ -403,7 +403,7 @@ impl<'a, 'b> PatternTyper<'a, 'b> {
); );
match instantiated_constructor_type.deref() { match instantiated_constructor_type.deref() {
Type::Fn { args, ret } => { Type::Fn { args, ret, .. } => {
if with_spread && has_no_fields { if with_spread && has_no_fields {
if pattern_args.len() == args.len() { if pattern_args.len() == args.len() {
return Err(Error::UnnecessarySpreadOperator { return Err(Error::UnnecessarySpreadOperator {

View File

@ -1,12 +1,10 @@
use std::{collections::HashMap, rc::Rc};
use itertools::Itertools;
use super::{Type, TypeVar}; use super::{Type, TypeVar};
use crate::{ use crate::{
docvec, docvec,
pretty::{nil, *}, pretty::{nil, *},
}; };
use itertools::Itertools;
use std::{collections::HashMap, rc::Rc};
const INDENT: isize = 2; const INDENT: isize = 2;
@ -50,8 +48,14 @@ impl Printer {
pub fn print<'a>(&mut self, typ: &Type) -> Document<'a> { pub fn print<'a>(&mut self, typ: &Type) -> Document<'a> {
match typ { match typ {
Type::App { Type::App {
name, args, module, .. name,
} => { args,
module,
alias,
..
} => match alias {
Some(alias) => self.type_alias_doc(alias.clone()),
None => {
let doc = if self.name_clashes_if_unqualified(name, module) { let doc = if self.name_clashes_if_unqualified(name, module) {
qualify_type_name(module, name) qualify_type_name(module, name)
} else { } else {
@ -66,19 +70,53 @@ impl Printer {
.append(">") .append(">")
} }
} }
},
Type::Fn { args, ret } => "fn(" Type::Fn { args, ret, alias } => match alias {
Some(alias) => self.type_alias_doc(alias.clone()),
None => "fn("
.to_doc() .to_doc()
.append(self.args_to_aiken_doc(args)) .append(self.args_to_aiken_doc(args))
.append(") ->") .append(") ->")
.append(break_("", " ").append(self.print(ret)).nest(INDENT).group()), .append(break_("", " ").append(self.print(ret)).nest(INDENT).group()),
},
Type::Var { tipo: typ, .. } => self.type_var_doc(&typ.borrow()), Type::Var { tipo: typ, alias } => match alias {
Some(alias) => self.type_alias_doc(alias.clone()),
None => self.type_var_doc(&typ.borrow()),
},
Type::Tuple { elems, .. } => self.args_to_aiken_doc(elems).surround("(", ")"), Type::Tuple { elems, alias } => match alias {
Some(alias) => self.type_alias_doc(alias.clone()),
None => self.args_to_aiken_doc(elems).surround("(", ")"),
},
} }
} }
fn type_alias_doc<'a>(&mut self, alias: (String, Vec<String>)) -> Document<'a> {
let mut doc = Document::String(alias.0.to_owned());
if !alias.1.is_empty() {
let args = concat(Itertools::intersperse(
alias.1.into_iter().map(Document::String),
break_(",", ", "),
));
doc = doc
.append("<")
.append(
break_("", "")
.append(args)
.nest(INDENT)
.append(break_(",", ""))
.group(),
)
.append(">");
}
doc
}
fn name_clashes_if_unqualified(&mut self, tipo: &String, module: &String) -> bool { fn name_clashes_if_unqualified(&mut self, tipo: &String, module: &String) -> bool {
match self.printed_types.get(tipo) { match self.printed_types.get(tipo) {
None => false, None => false,
@ -169,13 +207,10 @@ fn qualify_type_name(module: &String, typ_name: &str) -> Document<'static> {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use std::cell::RefCell;
use pretty_assertions::assert_eq;
use crate::builtins::{function, int};
use super::*; use super::*;
use crate::builtins::{function, int};
use pretty_assertions::assert_eq;
use std::cell::RefCell;
#[test] #[test]
fn next_letter_test() { fn next_letter_test() {
@ -275,6 +310,7 @@ mod tests {
name: "Int".to_string(), name: "Int".to_string(),
public: true, public: true,
args: vec![], args: vec![],
alias: None
}, },
"Int", "Int",
); );
@ -283,18 +319,21 @@ mod tests {
module: "".to_string(), module: "".to_string(),
name: "Pair".to_string(), name: "Pair".to_string(),
public: true, public: true,
alias: None,
args: vec![ args: vec![
Rc::new(Type::App { Rc::new(Type::App {
module: "whatever".to_string(), module: "whatever".to_string(),
name: "Int".to_string(), name: "Int".to_string(),
public: true, public: true,
args: vec![], args: vec![],
alias: None
}), }),
Rc::new(Type::App { Rc::new(Type::App {
module: "whatever".to_string(), module: "whatever".to_string(),
name: "Bool".to_string(), name: "Bool".to_string(),
public: true, public: true,
args: vec![], args: vec![],
alias: None
}), }),
], ],
}, },
@ -308,12 +347,14 @@ mod tests {
module: "whatever".to_string(), module: "whatever".to_string(),
name: "Int".to_string(), name: "Int".to_string(),
public: true, public: true,
alias: None,
}), }),
Rc::new(Type::App { Rc::new(Type::App {
args: vec![], args: vec![],
module: "whatever".to_string(), module: "whatever".to_string(),
name: "Bool".to_string(), name: "Bool".to_string(),
public: true, public: true,
alias: None,
}), }),
], ],
ret: Rc::new(Type::App { ret: Rc::new(Type::App {
@ -321,14 +362,18 @@ mod tests {
module: "whatever".to_string(), module: "whatever".to_string(),
name: "Bool".to_string(), name: "Bool".to_string(),
public: true, public: true,
alias: None,
}), }),
alias: None,
}, },
"fn(Int, Bool) -> Bool", "fn(Int, Bool) -> Bool",
); );
assert_string!( assert_string!(
Type::Var { Type::Var {
alias: None,
tipo: Rc::new(RefCell::new(TypeVar::Link { tipo: Rc::new(RefCell::new(TypeVar::Link {
tipo: Rc::new(Type::App { tipo: Rc::new(Type::App {
alias: None,
args: vec![], args: vec![],
module: "whatever".to_string(), module: "whatever".to_string(),
name: "Int".to_string(), name: "Int".to_string(),
@ -341,6 +386,7 @@ mod tests {
assert_string!( assert_string!(
Type::Var { Type::Var {
tipo: Rc::new(RefCell::new(TypeVar::Unbound { id: 2231 })), tipo: Rc::new(RefCell::new(TypeVar::Unbound { id: 2231 })),
alias: None,
}, },
"a", "a",
); );
@ -348,9 +394,11 @@ mod tests {
function( function(
vec![Rc::new(Type::Var { vec![Rc::new(Type::Var {
tipo: Rc::new(RefCell::new(TypeVar::Unbound { id: 78 })), tipo: Rc::new(RefCell::new(TypeVar::Unbound { id: 78 })),
alias: None,
})], })],
Rc::new(Type::Var { Rc::new(Type::Var {
tipo: Rc::new(RefCell::new(TypeVar::Unbound { id: 2 })), tipo: Rc::new(RefCell::new(TypeVar::Unbound { id: 2 })),
alias: None,
}), }),
), ),
"fn(a) -> b", "fn(a) -> b",
@ -359,9 +407,11 @@ mod tests {
function( function(
vec![Rc::new(Type::Var { vec![Rc::new(Type::Var {
tipo: Rc::new(RefCell::new(TypeVar::Generic { id: 78 })), tipo: Rc::new(RefCell::new(TypeVar::Generic { id: 78 })),
alias: None,
})], })],
Rc::new(Type::Var { Rc::new(Type::Var {
tipo: Rc::new(RefCell::new(TypeVar::Generic { id: 2 })), tipo: Rc::new(RefCell::new(TypeVar::Generic { id: 2 })),
alias: None,
}), }),
), ),
"fn(a) -> b", "fn(a) -> b",

View File

@ -139,7 +139,7 @@ impl Reference {
} }
} }
Type::Tuple { elems } => Self { Type::Tuple { elems, .. } => Self {
inner: format!( inner: format!(
"Tuple{elems}", "Tuple{elems}",
elems = Self::from_types(elems, type_parameters) elems = Self::from_types(elems, type_parameters)
@ -150,7 +150,7 @@ impl Reference {
// //
// Implementations below are only there for completeness. In practice, we should never // Implementations below are only there for completeness. In practice, we should never
// end up creating references for 'Var' or 'Fn' in the context of blueprints. // end up creating references for 'Var' or 'Fn' in the context of blueprints.
Type::Var { tipo } => match tipo.borrow().deref() { Type::Var { tipo, .. } => match tipo.borrow().deref() {
TypeVar::Link { tipo } => Self::from_type(tipo.as_ref(), type_parameters), TypeVar::Link { tipo } => Self::from_type(tipo.as_ref(), type_parameters),
TypeVar::Generic { id } | TypeVar::Unbound { id } => { TypeVar::Generic { id } | TypeVar::Unbound { id } => {
let tipo = type_parameters.get(id).unwrap(); let tipo = type_parameters.get(id).unwrap();
@ -158,7 +158,7 @@ impl Reference {
} }
}, },
Type::Fn { args, ret } => Self { Type::Fn { args, ret, .. } => Self {
inner: format!( inner: format!(
"Fn{args}_{ret}", "Fn{args}_{ret}",
args = Self::from_types(args, type_parameters), args = Self::from_types(args, type_parameters),

View File

@ -350,7 +350,7 @@ impl Annotated<Schema> {
annotated, annotated,
}) })
}), }),
Type::Tuple { elems } => { Type::Tuple { elems, .. } => {
definitions.register(type_info, &type_parameters.clone(), |definitions| { definitions.register(type_info, &type_parameters.clone(), |definitions| {
let elems = elems let elems = elems
.iter() .iter()
@ -368,7 +368,7 @@ impl Annotated<Schema> {
}) })
}) })
} }
Type::Var { tipo } => match tipo.borrow().deref() { Type::Var { tipo, .. } => match tipo.borrow().deref() {
TypeVar::Link { tipo } => { TypeVar::Link { tipo } => {
Annotated::do_from_type(tipo, modules, type_parameters, definitions) Annotated::do_from_type(tipo, modules, type_parameters, definitions)
} }
@ -440,7 +440,7 @@ fn collect_type_parameters<'a>(
) { ) {
for (index, generic) in generics.iter().enumerate() { for (index, generic) in generics.iter().enumerate() {
match &**generic { match &**generic {
Type::Var { tipo } => match *tipo.borrow() { Type::Var { tipo, .. } => match *tipo.borrow() {
TypeVar::Generic { id } => { TypeVar::Generic { id } => {
type_parameters.insert( type_parameters.insert(
id, id,
@ -1125,11 +1125,13 @@ pub mod tests {
#[test] #[test]
fn serialize_data_constr_1() { fn serialize_data_constr_1() {
let schema = Schema::Data(Data::AnyOf(vec![Constructor { let schema = Schema::Data(Data::AnyOf(vec![
Constructor {
index: 0, index: 0,
fields: vec![], fields: vec![],
} }
.into()])); .into(),
]));
assert_json( assert_json(
&schema, &schema,
json!({ json!({
@ -1290,14 +1292,16 @@ pub mod tests {
#[test] #[test]
fn deserialize_any_of() { fn deserialize_any_of() {
assert_eq!( assert_eq!(
Data::AnyOf(vec![Constructor { Data::AnyOf(vec![
Constructor {
index: 0, index: 0,
fields: vec![ fields: vec![
Declaration::Referenced(Reference::new("foo")).into(), Declaration::Referenced(Reference::new("foo")).into(),
Declaration::Referenced(Reference::new("bar")).into() Declaration::Referenced(Reference::new("bar")).into()
], ],
} }
.into()]), .into()
]),
serde_json::from_value(json!({ serde_json::from_value(json!({
"anyOf": [{ "anyOf": [{
"index": 0, "index": 0,
@ -1318,14 +1322,16 @@ pub mod tests {
#[test] #[test]
fn deserialize_one_of() { fn deserialize_one_of() {
assert_eq!( assert_eq!(
Data::AnyOf(vec![Constructor { Data::AnyOf(vec![
Constructor {
index: 0, index: 0,
fields: vec![ fields: vec![
Declaration::Referenced(Reference::new("foo")).into(), Declaration::Referenced(Reference::new("foo")).into(),
Declaration::Referenced(Reference::new("bar")).into() Declaration::Referenced(Reference::new("bar")).into()
], ],
} }
.into()]), .into()
]),
serde_json::from_value(json!({ serde_json::from_value(json!({
"oneOf": [{ "oneOf": [{
"index": 0, "index": 0,