Resolve type aliases based on inferred types.
Before this commit, we would always show the 'declared form' of type aliases, with their generic, non-instantiated parameters. This now tries to unify the annotation with the underlying inferred type to provide even better alias pretty printing.
This commit is contained in:
parent
ed9f5c6ef7
commit
a578728a94
|
@ -1,12 +1,12 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
ast::{
|
ast::{
|
||||||
Arg, ArgName, CallArg, DataTypeKey, Function, FunctionAccessKey, ModuleKind, Span,
|
Annotation, Arg, ArgName, CallArg, DataTypeKey, Function, FunctionAccessKey, ModuleKind,
|
||||||
TypedDataType, TypedFunction, UnOp,
|
Span, TypedDataType, TypedFunction, UnOp,
|
||||||
},
|
},
|
||||||
expr::TypedExpr,
|
expr::TypedExpr,
|
||||||
tipo::{
|
tipo::{
|
||||||
fields::FieldMap, Type, TypeConstructor, TypeInfo, TypeVar, ValueConstructor,
|
fields::FieldMap, Type, TypeAliasAnnotation, TypeConstructor, TypeInfo, TypeVar,
|
||||||
ValueConstructorVariant,
|
ValueConstructor, ValueConstructorVariant,
|
||||||
},
|
},
|
||||||
IdGenerator,
|
IdGenerator,
|
||||||
};
|
};
|
||||||
|
@ -1349,10 +1349,42 @@ pub fn prng() -> Rc<Type> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn fuzzer(a: Rc<Type>) -> Rc<Type> {
|
pub fn fuzzer(a: Rc<Type>) -> Rc<Type> {
|
||||||
|
let prng_annotation = Annotation::Constructor {
|
||||||
|
location: Span::empty(),
|
||||||
|
module: None,
|
||||||
|
name: "PRNG".to_string(),
|
||||||
|
arguments: vec![],
|
||||||
|
};
|
||||||
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()])),
|
alias: Some(
|
||||||
|
TypeAliasAnnotation {
|
||||||
|
alias: "Fuzzer".to_string(),
|
||||||
|
parameters: vec!["a".to_string()],
|
||||||
|
annotation: Annotation::Fn {
|
||||||
|
location: Span::empty(),
|
||||||
|
arguments: vec![prng_annotation.clone()],
|
||||||
|
ret: Annotation::Constructor {
|
||||||
|
location: Span::empty(),
|
||||||
|
module: None,
|
||||||
|
name: "Option".to_string(),
|
||||||
|
arguments: vec![Annotation::Tuple {
|
||||||
|
location: Span::empty(),
|
||||||
|
elems: vec![
|
||||||
|
prng_annotation,
|
||||||
|
Annotation::Var {
|
||||||
|
location: Span::empty(),
|
||||||
|
name: "a".to_string(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}],
|
||||||
|
}
|
||||||
|
.into(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
.into(),
|
||||||
|
),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,13 @@ mod pattern;
|
||||||
mod pipe;
|
mod pipe;
|
||||||
pub mod pretty;
|
pub mod pretty;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct TypeAliasAnnotation {
|
||||||
|
pub alias: String,
|
||||||
|
pub parameters: Vec<String>,
|
||||||
|
pub annotation: Annotation,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[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
|
||||||
|
@ -38,7 +45,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>)>,
|
alias: Option<Rc<TypeAliasAnnotation>>,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// The type of a function. It takes arguments and returns a value.
|
/// The type of a function. It takes arguments and returns a value.
|
||||||
|
@ -46,14 +53,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>)>,
|
alias: Option<Rc<TypeAliasAnnotation>>,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// 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>)>,
|
alias: Option<Rc<TypeAliasAnnotation>>,
|
||||||
},
|
},
|
||||||
// /// 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
|
||||||
|
@ -61,7 +68,7 @@ pub enum Type {
|
||||||
// ///
|
// ///
|
||||||
Tuple {
|
Tuple {
|
||||||
elems: Vec<Rc<Type>>,
|
elems: Vec<Rc<Type>>,
|
||||||
alias: Option<(String, Vec<String>)>,
|
alias: Option<Rc<TypeAliasAnnotation>>,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,15 +132,23 @@ impl PartialEq for Type {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Type {
|
impl Type {
|
||||||
pub fn with_alias(tipo: Rc<Type>, alias: &Option<(String, Vec<String>)>) -> Rc<Type> {
|
pub fn alias(&self) -> Option<Rc<TypeAliasAnnotation>> {
|
||||||
match alias {
|
match self {
|
||||||
None => tipo,
|
Type::App { alias, .. }
|
||||||
Some((name, args)) => tipo.as_ref().to_owned().set_alias(name, args),
|
| Type::Fn { alias, .. }
|
||||||
|
| Type::Var { alias, .. }
|
||||||
|
| Type::Tuple { alias, .. } => alias.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_alias(self, name: &str, args: &[String]) -> Rc<Type> {
|
pub fn with_alias(tipo: Rc<Type>, alias: Option<Rc<TypeAliasAnnotation>>) -> Rc<Type> {
|
||||||
let alias = Some((name.to_string(), args.to_vec()));
|
match alias {
|
||||||
|
None => tipo,
|
||||||
|
Some(alias) => tipo.deref().to_owned().set_alias(Some(alias)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_alias(self, alias: Option<Rc<TypeAliasAnnotation>>) -> Rc<Type> {
|
||||||
Rc::new(match self {
|
Rc::new(match self {
|
||||||
Type::App {
|
Type::App {
|
||||||
public,
|
public,
|
||||||
|
@ -939,13 +954,11 @@ 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![
|
vec![Type::Var {
|
||||||
Type::Var {
|
|
||||||
tipo: RefCell::new(var.clone()).into(),
|
tipo: RefCell::new(var.clone()).into(),
|
||||||
alias: None,
|
alias: None,
|
||||||
}
|
}
|
||||||
.into(),
|
.into()]
|
||||||
]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ use crate::{
|
||||||
UnqualifiedImport, UntypedArg, UntypedDefinition, Use, Validator, PIPE_VARIABLE,
|
UnqualifiedImport, UntypedArg, UntypedDefinition, Use, Validator, PIPE_VARIABLE,
|
||||||
},
|
},
|
||||||
builtins::{function, generic_var, tuple, unbound_var},
|
builtins::{function, generic_var, tuple, unbound_var},
|
||||||
tipo::fields::FieldMap,
|
tipo::{fields::FieldMap, TypeAliasAnnotation},
|
||||||
IdGenerator,
|
IdGenerator,
|
||||||
};
|
};
|
||||||
use std::{
|
use std::{
|
||||||
|
@ -567,7 +567,7 @@ impl<'a> Environment<'a> {
|
||||||
TypeVar::Link { tipo } => {
|
TypeVar::Link { tipo } => {
|
||||||
return Type::with_alias(
|
return Type::with_alias(
|
||||||
self.instantiate(tipo.clone(), ids, hydrator),
|
self.instantiate(tipo.clone(), ids, hydrator),
|
||||||
alias,
|
alias.clone(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -603,7 +603,7 @@ impl<'a> Environment<'a> {
|
||||||
.collect(),
|
.collect(),
|
||||||
self.instantiate(ret.clone(), ids, hydrator),
|
self.instantiate(ret.clone(), ids, hydrator),
|
||||||
),
|
),
|
||||||
alias,
|
alias.clone(),
|
||||||
),
|
),
|
||||||
|
|
||||||
Type::Tuple { elems, alias } => Type::with_alias(
|
Type::Tuple { elems, alias } => Type::with_alias(
|
||||||
|
@ -613,7 +613,7 @@ impl<'a> Environment<'a> {
|
||||||
.map(|t| self.instantiate(t.clone(), ids, hydrator))
|
.map(|t| self.instantiate(t.clone(), ids, hydrator))
|
||||||
.collect(),
|
.collect(),
|
||||||
),
|
),
|
||||||
alias,
|
alias.clone(),
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1046,7 +1046,14 @@ impl<'a> Environment<'a> {
|
||||||
.type_from_annotation(resolved_type, self)?
|
.type_from_annotation(resolved_type, self)?
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.to_owned()
|
.to_owned()
|
||||||
.set_alias(name, args);
|
.set_alias(Some(
|
||||||
|
TypeAliasAnnotation {
|
||||||
|
alias: name.to_string(),
|
||||||
|
parameters: args.to_vec(),
|
||||||
|
annotation: resolved_type.clone(),
|
||||||
|
}
|
||||||
|
.into(),
|
||||||
|
));
|
||||||
|
|
||||||
self.insert_type_constructor(
|
self.insert_type_constructor(
|
||||||
name.clone(),
|
name.clone(),
|
||||||
|
@ -1842,7 +1849,7 @@ pub(crate) fn generalise(t: Rc<Type>, ctx_level: usize) -> Rc<Type> {
|
||||||
alias: None,
|
alias: None,
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
alias,
|
alias.clone(),
|
||||||
),
|
),
|
||||||
|
|
||||||
Type::App {
|
Type::App {
|
||||||
|
@ -1873,7 +1880,7 @@ pub(crate) fn generalise(t: Rc<Type>, ctx_level: usize) -> Rc<Type> {
|
||||||
.collect(),
|
.collect(),
|
||||||
generalise(ret.clone(), ctx_level),
|
generalise(ret.clone(), ctx_level),
|
||||||
),
|
),
|
||||||
alias,
|
alias.clone(),
|
||||||
),
|
),
|
||||||
|
|
||||||
Type::Tuple { elems, alias } => Type::with_alias(
|
Type::Tuple { elems, alias } => Type::with_alias(
|
||||||
|
@ -1883,7 +1890,7 @@ pub(crate) fn generalise(t: Rc<Type>, ctx_level: usize) -> Rc<Type> {
|
||||||
.map(|t| generalise(t.clone(), ctx_level))
|
.map(|t| generalise(t.clone(), ctx_level))
|
||||||
.collect(),
|
.collect(),
|
||||||
),
|
),
|
||||||
alias,
|
alias.clone(),
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -608,7 +608,11 @@ 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![], alias: None }.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(),
|
||||||
|
|
|
@ -2,6 +2,7 @@ use super::{Type, TypeVar};
|
||||||
use crate::{
|
use crate::{
|
||||||
docvec,
|
docvec,
|
||||||
pretty::{nil, *},
|
pretty::{nil, *},
|
||||||
|
tipo::{Annotation, TypeAliasAnnotation},
|
||||||
};
|
};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use std::{collections::HashMap, rc::Rc};
|
use std::{collections::HashMap, rc::Rc};
|
||||||
|
@ -46,16 +47,21 @@ impl Printer {
|
||||||
// Is this possible? The lifetime would have to go through the Rc<Refcell<Type>>
|
// Is this possible? The lifetime would have to go through the Rc<Refcell<Type>>
|
||||||
// for TypeVar::Link'd types.
|
// for TypeVar::Link'd types.
|
||||||
pub fn print<'a>(&mut self, typ: &Type) -> Document<'a> {
|
pub fn print<'a>(&mut self, typ: &Type) -> Document<'a> {
|
||||||
|
if let Some(TypeAliasAnnotation {
|
||||||
|
alias,
|
||||||
|
parameters,
|
||||||
|
annotation,
|
||||||
|
}) = typ.alias().as_deref()
|
||||||
|
{
|
||||||
|
if let Some(resolved_parameters) = resolve_alias(parameters, annotation, typ) {
|
||||||
|
return self.type_alias_doc(alias.to_string(), resolved_parameters);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
match typ {
|
match typ {
|
||||||
Type::App {
|
Type::App {
|
||||||
name,
|
name, args, module, ..
|
||||||
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 {
|
||||||
|
@ -70,52 +76,38 @@ impl Printer {
|
||||||
.append(">")
|
.append(">")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
|
|
||||||
Type::Fn { args, ret, alias } => match alias {
|
Type::Fn { args, ret, .. } => "fn("
|
||||||
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, alias } => match alias {
|
Type::Var { tipo: typ, .. } => self.type_var_doc(&typ.borrow()),
|
||||||
Some(alias) => self.type_alias_doc(alias.clone()),
|
|
||||||
None => self.type_var_doc(&typ.borrow()),
|
|
||||||
},
|
|
||||||
|
|
||||||
Type::Tuple { elems, alias } => match alias {
|
Type::Tuple { elems, .. } => self.args_to_aiken_doc(elems).surround("(", ")"),
|
||||||
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> {
|
fn type_alias_doc<'a>(&mut self, alias: String, parameters: Vec<Rc<Type>>) -> Document<'a> {
|
||||||
let mut doc = Document::String(alias.0.to_owned());
|
let doc = Document::String(alias);
|
||||||
|
|
||||||
if !alias.1.is_empty() {
|
if !parameters.is_empty() {
|
||||||
let args = concat(Itertools::intersperse(
|
doc.append(
|
||||||
alias.1.into_iter().map(Document::String),
|
|
||||||
break_(",", ", "),
|
|
||||||
));
|
|
||||||
|
|
||||||
doc = doc
|
|
||||||
.append("<")
|
|
||||||
.append(
|
|
||||||
break_("", "")
|
break_("", "")
|
||||||
.append(args)
|
.append(concat(Itertools::intersperse(
|
||||||
|
parameters.iter().map(|t| self.print(t)),
|
||||||
|
break_(",", ", "),
|
||||||
|
)))
|
||||||
.nest(INDENT)
|
.nest(INDENT)
|
||||||
.append(break_(",", ""))
|
.append(break_(",", ""))
|
||||||
.group(),
|
.group()
|
||||||
|
.surround("<", ">"),
|
||||||
)
|
)
|
||||||
.append(">");
|
} else {
|
||||||
}
|
|
||||||
|
|
||||||
doc
|
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) {
|
||||||
|
@ -205,10 +197,77 @@ fn qualify_type_name(module: &String, typ_name: &str) -> Document<'static> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn resolve_alias(
|
||||||
|
parameters: &[String],
|
||||||
|
annotation: &Annotation,
|
||||||
|
typ: &Type,
|
||||||
|
) -> Option<Vec<Rc<Type>>> {
|
||||||
|
let mut types = Vec::new();
|
||||||
|
|
||||||
|
fn resolve_one(parameter: &str, annotation: &Annotation, typ: Rc<Type>) -> Option<Rc<Type>> {
|
||||||
|
match (annotation, typ.as_ref()) {
|
||||||
|
(
|
||||||
|
Annotation::Fn {
|
||||||
|
arguments: args,
|
||||||
|
ret,
|
||||||
|
..
|
||||||
|
},
|
||||||
|
Type::Fn {
|
||||||
|
args: t_args,
|
||||||
|
ret: t_ret,
|
||||||
|
..
|
||||||
|
},
|
||||||
|
) => {
|
||||||
|
let mut result = resolve_one(parameter, ret, t_ret.clone());
|
||||||
|
for (ann, t) in args.iter().zip(t_args) {
|
||||||
|
result = result.or_else(|| resolve_one(parameter, ann, t.clone()));
|
||||||
|
}
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
(
|
||||||
|
Annotation::Constructor {
|
||||||
|
arguments: args, ..
|
||||||
|
},
|
||||||
|
Type::App { args: t_args, .. },
|
||||||
|
) => {
|
||||||
|
let mut result = None;
|
||||||
|
for (ann, t) in args.iter().zip(t_args) {
|
||||||
|
result = result.or_else(|| resolve_one(parameter, ann, t.clone()));
|
||||||
|
}
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
(Annotation::Tuple { elems, .. }, Type::Tuple { elems: t_elems, .. }) => {
|
||||||
|
let mut result = None;
|
||||||
|
for (ann, t) in elems.iter().zip(t_elems) {
|
||||||
|
result = result.or_else(|| resolve_one(parameter, ann, t.clone()));
|
||||||
|
}
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
(Annotation::Var { name, .. }, ..) if name == parameter => Some(typ),
|
||||||
|
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let rc: Rc<Type> = typ.to_owned().into();
|
||||||
|
|
||||||
|
for parameter in parameters {
|
||||||
|
types.push(resolve_one(parameter, annotation, rc.clone())?);
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(types)
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::builtins::{function, int};
|
use crate::{
|
||||||
|
builtins::{function, int},
|
||||||
|
tipo::Span,
|
||||||
|
};
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
|
|
||||||
|
@ -416,6 +475,143 @@ mod tests {
|
||||||
),
|
),
|
||||||
"fn(a) -> b",
|
"fn(a) -> b",
|
||||||
);
|
);
|
||||||
|
assert_string!(
|
||||||
|
Type::Fn {
|
||||||
|
args: vec![Rc::new(Type::App {
|
||||||
|
public: true,
|
||||||
|
module: "".to_string(),
|
||||||
|
name: "PRNG".to_string(),
|
||||||
|
args: vec![],
|
||||||
|
alias: None,
|
||||||
|
})],
|
||||||
|
ret: Rc::new(Type::App {
|
||||||
|
public: true,
|
||||||
|
module: "".to_string(),
|
||||||
|
name: "Option".to_string(),
|
||||||
|
args: vec![Rc::new(Type::Tuple {
|
||||||
|
elems: vec![
|
||||||
|
Rc::new(Type::App {
|
||||||
|
public: true,
|
||||||
|
module: "".to_string(),
|
||||||
|
name: "PRNG".to_string(),
|
||||||
|
args: vec![],
|
||||||
|
alias: None,
|
||||||
|
}),
|
||||||
|
Rc::new(Type::App {
|
||||||
|
public: true,
|
||||||
|
module: "".to_string(),
|
||||||
|
name: "Bool".to_string(),
|
||||||
|
args: vec![],
|
||||||
|
alias: None,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
alias: None,
|
||||||
|
})],
|
||||||
|
alias: None,
|
||||||
|
}),
|
||||||
|
alias: Some(Rc::new(TypeAliasAnnotation {
|
||||||
|
alias: "Fuzzer".to_string(),
|
||||||
|
parameters: vec!["a".to_string(),],
|
||||||
|
annotation: Annotation::Fn {
|
||||||
|
location: Span::empty(),
|
||||||
|
arguments: vec![Annotation::Constructor {
|
||||||
|
location: Span::empty(),
|
||||||
|
module: None,
|
||||||
|
name: "PRNG".to_string(),
|
||||||
|
arguments: vec![],
|
||||||
|
},],
|
||||||
|
ret: Box::new(Annotation::Constructor {
|
||||||
|
location: Span::empty(),
|
||||||
|
module: None,
|
||||||
|
name: "Option".to_string(),
|
||||||
|
arguments: vec![Annotation::Tuple {
|
||||||
|
location: Span::empty(),
|
||||||
|
elems: vec![
|
||||||
|
Annotation::Constructor {
|
||||||
|
location: Span::empty(),
|
||||||
|
module: None,
|
||||||
|
name: "PRNG".to_string(),
|
||||||
|
arguments: vec![],
|
||||||
|
},
|
||||||
|
Annotation::Var {
|
||||||
|
location: Span::empty(),
|
||||||
|
name: "a".to_string(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}],
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
})),
|
||||||
|
},
|
||||||
|
"Fuzzer<Bool>",
|
||||||
|
);
|
||||||
|
assert_string!(
|
||||||
|
Type::Fn {
|
||||||
|
args: vec![Rc::new(Type::App {
|
||||||
|
public: true,
|
||||||
|
module: "".to_string(),
|
||||||
|
name: "PRNG".to_string(),
|
||||||
|
args: vec![],
|
||||||
|
alias: None,
|
||||||
|
})],
|
||||||
|
ret: Rc::new(Type::App {
|
||||||
|
public: true,
|
||||||
|
module: "".to_string(),
|
||||||
|
name: "Option".to_string(),
|
||||||
|
args: vec![Rc::new(Type::Tuple {
|
||||||
|
elems: vec![
|
||||||
|
Rc::new(Type::App {
|
||||||
|
public: true,
|
||||||
|
module: "".to_string(),
|
||||||
|
name: "PRNG".to_string(),
|
||||||
|
args: vec![],
|
||||||
|
alias: None,
|
||||||
|
}),
|
||||||
|
Rc::new(Type::Var {
|
||||||
|
tipo: Rc::new(RefCell::new(TypeVar::Generic { id: 0 })),
|
||||||
|
alias: None,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
alias: None,
|
||||||
|
})],
|
||||||
|
alias: None,
|
||||||
|
}),
|
||||||
|
alias: Some(Rc::new(TypeAliasAnnotation {
|
||||||
|
alias: "Fuzzer".to_string(),
|
||||||
|
parameters: vec!["a".to_string(),],
|
||||||
|
annotation: Annotation::Fn {
|
||||||
|
location: Span::empty(),
|
||||||
|
arguments: vec![Annotation::Constructor {
|
||||||
|
location: Span::empty(),
|
||||||
|
module: None,
|
||||||
|
name: "PRNG".to_string(),
|
||||||
|
arguments: vec![],
|
||||||
|
},],
|
||||||
|
ret: Box::new(Annotation::Constructor {
|
||||||
|
location: Span::empty(),
|
||||||
|
module: None,
|
||||||
|
name: "Option".to_string(),
|
||||||
|
arguments: vec![Annotation::Tuple {
|
||||||
|
location: Span::empty(),
|
||||||
|
elems: vec![
|
||||||
|
Annotation::Constructor {
|
||||||
|
location: Span::empty(),
|
||||||
|
module: None,
|
||||||
|
name: "PRNG".to_string(),
|
||||||
|
arguments: vec![],
|
||||||
|
},
|
||||||
|
Annotation::Var {
|
||||||
|
location: Span::empty(),
|
||||||
|
name: "a".to_string(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}],
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
})),
|
||||||
|
},
|
||||||
|
"Fuzzer<a>",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -1,10 +1,14 @@
|
||||||
use crate::quickfix::Quickfix;
|
use self::lsp_project::LspProject;
|
||||||
use std::{
|
use crate::{
|
||||||
collections::{HashMap, HashSet},
|
cast::{cast_notification, cast_request},
|
||||||
fs,
|
error::Error as ServerError,
|
||||||
path::{Path, PathBuf},
|
quickfix,
|
||||||
|
quickfix::Quickfix,
|
||||||
|
utils::{
|
||||||
|
path_to_uri, span_to_lsp_range, text_edit_replace, uri_to_module_name,
|
||||||
|
COMPILING_PROGRESS_TOKEN, CREATE_COMPILING_PROGRESS_TOKEN,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
use aiken_lang::{
|
use aiken_lang::{
|
||||||
ast::{Definition, Located, ModuleKind, Span, Use},
|
ast::{Definition, Located, ModuleKind, Span, Use},
|
||||||
error::ExtraData,
|
error::ExtraData,
|
||||||
|
@ -32,19 +36,12 @@ use lsp_types::{
|
||||||
DocumentFormattingParams, InitializeParams, TextEdit,
|
DocumentFormattingParams, InitializeParams, TextEdit,
|
||||||
};
|
};
|
||||||
use miette::Diagnostic;
|
use miette::Diagnostic;
|
||||||
|
use std::{
|
||||||
use crate::{
|
collections::{HashMap, HashSet},
|
||||||
cast::{cast_notification, cast_request},
|
fs,
|
||||||
error::Error as ServerError,
|
path::{Path, PathBuf},
|
||||||
quickfix,
|
|
||||||
utils::{
|
|
||||||
path_to_uri, span_to_lsp_range, text_edit_replace, uri_to_module_name,
|
|
||||||
COMPILING_PROGRESS_TOKEN, CREATE_COMPILING_PROGRESS_TOKEN,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use self::lsp_project::LspProject;
|
|
||||||
|
|
||||||
pub mod lsp_project;
|
pub mod lsp_project;
|
||||||
pub mod telemetry;
|
pub mod telemetry;
|
||||||
|
|
||||||
|
|
|
@ -1125,13 +1125,11 @@ pub mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn serialize_data_constr_1() {
|
fn serialize_data_constr_1() {
|
||||||
let schema = Schema::Data(Data::AnyOf(vec![
|
let schema = Schema::Data(Data::AnyOf(vec![Constructor {
|
||||||
Constructor {
|
|
||||||
index: 0,
|
index: 0,
|
||||||
fields: vec![],
|
fields: vec![],
|
||||||
}
|
}
|
||||||
.into(),
|
.into()]));
|
||||||
]));
|
|
||||||
assert_json(
|
assert_json(
|
||||||
&schema,
|
&schema,
|
||||||
json!({
|
json!({
|
||||||
|
@ -1292,16 +1290,14 @@ pub mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn deserialize_any_of() {
|
fn deserialize_any_of() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Data::AnyOf(vec![
|
Data::AnyOf(vec![Constructor {
|
||||||
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,
|
||||||
|
@ -1322,16 +1318,14 @@ pub mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn deserialize_one_of() {
|
fn deserialize_one_of() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Data::AnyOf(vec![
|
Data::AnyOf(vec![Constructor {
|
||||||
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,
|
||||||
|
|
|
@ -11,6 +11,7 @@ Schema {
|
||||||
module: "test_module",
|
module: "test_module",
|
||||||
name: "Rational",
|
name: "Rational",
|
||||||
args: [],
|
args: [],
|
||||||
|
alias: None,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
|
@ -19,9 +19,11 @@ Schema {
|
||||||
module: "test_module",
|
module: "test_module",
|
||||||
name: "UUID",
|
name: "UUID",
|
||||||
args: [],
|
args: [],
|
||||||
|
alias: None,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
alias: None,
|
||||||
},
|
},
|
||||||
Var {
|
Var {
|
||||||
tipo: RefCell {
|
tipo: RefCell {
|
||||||
|
@ -31,11 +33,14 @@ Schema {
|
||||||
module: "",
|
module: "",
|
||||||
name: "Int",
|
name: "Int",
|
||||||
args: [],
|
args: [],
|
||||||
|
alias: None,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
alias: None,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
alias: None,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in New Issue