Merge branch 'main' into when-clause-guards

This commit is contained in:
Lucas 2023-01-30 11:40:29 -05:00 committed by GitHub
commit b653714c0c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 2099 additions and 1015 deletions

1
Cargo.lock generated
View File

@ -117,6 +117,7 @@ dependencies = [
"futures", "futures",
"hex", "hex",
"ignore", "ignore",
"indexmap",
"itertools", "itertools",
"miette", "miette",
"owo-colors", "owo-colors",

View File

@ -1,5 +1,6 @@
use std::{collections::HashSet, sync::Arc}; use std::sync::Arc;
use indexmap::IndexSet;
use uplc::builtins::DefaultFunction; use uplc::builtins::DefaultFunction;
use crate::{ use crate::{
@ -9,6 +10,7 @@ use crate::{
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum Air { pub enum Air {
// Primitives
Int { Int {
scope: Vec<u64>, scope: Vec<u64>,
value: String, value: String,
@ -29,17 +31,6 @@ pub enum Air {
value: bool, value: bool,
}, },
Var {
scope: Vec<u64>,
constructor: ValueConstructor,
name: String,
variant_name: String,
},
Fn {
scope: Vec<u64>,
params: Vec<String>,
},
List { List {
scope: Vec<u64>, scope: Vec<u64>,
count: usize, count: usize,
@ -47,48 +38,30 @@ pub enum Air {
tail: bool, tail: bool,
}, },
ListAccessor { Tuple {
scope: Vec<u64>, scope: Vec<u64>,
tipo: Arc<Type>, tipo: Arc<Type>,
names: Vec<String>, count: usize,
tail: bool,
}, },
ListExpose { Void {
scope: Vec<u64>, scope: Vec<u64>,
tipo: Arc<Type>,
tail_head_names: Vec<(String, String)>,
tail: Option<(String, String)>,
}, },
Var {
scope: Vec<u64>,
constructor: ValueConstructor,
name: String,
variant_name: String,
},
// Functions
Call { Call {
scope: Vec<u64>, scope: Vec<u64>,
count: usize, count: usize,
},
Builtin {
scope: Vec<u64>,
func: DefaultFunction,
tipo: Arc<Type>, tipo: Arc<Type>,
}, },
BinOp {
scope: Vec<u64>,
name: BinOp,
count: usize,
tipo: Arc<Type>,
},
Assignment {
scope: Vec<u64>,
name: String,
},
Assert {
scope: Vec<u64>,
constr_index: usize,
},
DefineFunc { DefineFunc {
scope: Vec<u64>, scope: Vec<u64>,
func_name: String, func_name: String,
@ -98,11 +71,47 @@ pub enum Air {
variant_name: String, variant_name: String,
}, },
Lam { Fn {
scope: Vec<u64>,
params: Vec<String>,
},
Builtin {
scope: Vec<u64>,
func: DefaultFunction,
tipo: Arc<Type>,
},
// Operators
BinOp {
scope: Vec<u64>,
name: BinOp,
count: usize,
tipo: Arc<Type>,
},
UnOp {
scope: Vec<u64>,
op: UnOp,
},
// Assignment
Let {
scope: Vec<u64>, scope: Vec<u64>,
name: String, name: String,
}, },
UnWrapData {
scope: Vec<u64>,
tipo: Arc<Type>,
},
AssertConstr {
scope: Vec<u64>,
constr_index: usize,
},
// When
When { When {
scope: Vec<u64>, scope: Vec<u64>,
tipo: Arc<Type>, tipo: Arc<Type>,
@ -124,11 +133,15 @@ pub enum Air {
complex_clause: bool, complex_clause: bool,
}, },
WrapClause {
scope: Vec<u64>,
},
TupleClause { TupleClause {
scope: Vec<u64>, scope: Vec<u64>,
tipo: Arc<Type>, tipo: Arc<Type>,
indices: HashSet<(usize, String)>, indices: IndexSet<(usize, String)>,
predefined_indices: HashSet<(usize, String)>, predefined_indices: IndexSet<(usize, String)>,
subject_name: String, subject_name: String,
count: usize, count: usize,
complex_clause: bool, complex_clause: bool,
@ -148,18 +161,17 @@ pub enum Air {
inverse: bool, inverse: bool,
}, },
Discard {
scope: Vec<u64>,
},
Finally { Finally {
scope: Vec<u64>, scope: Vec<u64>,
}, },
// If
If { If {
scope: Vec<u64>, scope: Vec<u64>,
tipo: Arc<Type>,
}, },
// Record Creation
Record { Record {
scope: Vec<u64>, scope: Vec<u64>,
constr_index: usize, constr_index: usize,
@ -167,6 +179,14 @@ pub enum Air {
count: usize, count: usize,
}, },
RecordUpdate {
scope: Vec<u64>,
highest_index: usize,
indices: Vec<(usize, Arc<Type>)>,
tipo: Arc<Type>,
},
// Field Access
RecordAccess { RecordAccess {
scope: Vec<u64>, scope: Vec<u64>,
record_index: u64, record_index: u64,
@ -175,14 +195,32 @@ pub enum Air {
FieldsExpose { FieldsExpose {
scope: Vec<u64>, scope: Vec<u64>,
count: usize,
indices: Vec<(usize, String, Arc<Type>)>, indices: Vec<(usize, String, Arc<Type>)>,
check_last_item: bool,
}, },
Tuple { // ListAccess
ListAccessor {
scope: Vec<u64>, scope: Vec<u64>,
tipo: Arc<Type>, tipo: Arc<Type>,
count: usize, names: Vec<String>,
tail: bool,
check_last_item: bool,
},
ListExpose {
scope: Vec<u64>,
tipo: Arc<Type>,
tail_head_names: Vec<(String, String)>,
tail: Option<(String, String)>,
},
// Tuple Access
TupleAccessor {
scope: Vec<u64>,
names: Vec<String>,
tipo: Arc<Type>,
check_last_item: bool,
}, },
TupleIndex { TupleIndex {
@ -191,6 +229,7 @@ pub enum Air {
tuple_index: usize, tuple_index: usize,
}, },
// Misc.
Todo { Todo {
scope: Vec<u64>, scope: Vec<u64>,
label: Option<String>, label: Option<String>,
@ -208,23 +247,6 @@ pub enum Air {
text: Option<String>, text: Option<String>,
tipo: Arc<Type>, tipo: Arc<Type>,
}, },
RecordUpdate {
scope: Vec<u64>,
highest_index: usize,
indices: Vec<(usize, Arc<Type>)>,
},
UnOp {
scope: Vec<u64>,
op: UnOp,
},
TupleAccessor {
scope: Vec<u64>,
names: Vec<String>,
tipo: Arc<Type>,
},
} }
impl Air { impl Air {
@ -234,67 +256,142 @@ impl Air {
| Air::String { scope, .. } | Air::String { scope, .. }
| Air::ByteArray { scope, .. } | Air::ByteArray { scope, .. }
| Air::Bool { scope, .. } | Air::Bool { scope, .. }
| Air::Var { scope, .. }
| Air::List { scope, .. } | Air::List { scope, .. }
| Air::ListAccessor { scope, .. } | Air::Tuple { scope, .. }
| Air::ListExpose { scope, .. } | Air::Void { scope }
| Air::Fn { scope, .. } | Air::Var { scope, .. }
| Air::Call { scope, .. } | Air::Call { scope, .. }
| Air::DefineFunc { scope, .. }
| Air::Fn { scope, .. }
| Air::Builtin { scope, .. } | Air::Builtin { scope, .. }
| Air::BinOp { scope, .. } | Air::BinOp { scope, .. }
| Air::Assignment { scope, .. } | Air::UnOp { scope, .. }
| Air::Assert { scope, .. } | Air::Let { scope, .. }
| Air::DefineFunc { scope, .. } | Air::UnWrapData { scope, .. }
| Air::Lam { scope, .. } | Air::AssertConstr { scope, .. }
| Air::When { scope, .. } | Air::When { scope, .. }
| Air::Clause { scope, .. } | Air::Clause { scope, .. }
| Air::ListClause { scope, .. } | Air::ListClause { scope, .. }
| Air::WrapClause { scope }
| Air::TupleClause { scope, .. }
| Air::ClauseGuard { scope, .. } | Air::ClauseGuard { scope, .. }
| Air::ListClauseGuard { scope, .. } | Air::ListClauseGuard { scope, .. }
| Air::Discard { scope }
| Air::Finally { scope } | Air::Finally { scope }
| Air::If { scope, .. } | Air::If { scope, .. }
| Air::Record { scope, .. } | Air::Record { scope, .. }
| Air::RecordUpdate { scope, .. }
| Air::RecordAccess { scope, .. } | Air::RecordAccess { scope, .. }
| Air::FieldsExpose { scope, .. } | Air::FieldsExpose { scope, .. }
| Air::Tuple { scope, .. } | Air::ListAccessor { scope, .. }
| Air::Todo { scope, .. } | Air::ListExpose { scope, .. }
| Air::ErrorTerm { scope, .. }
| Air::RecordUpdate { scope, .. }
| Air::UnOp { scope, .. }
| Air::Trace { scope, .. }
| Air::TupleAccessor { scope, .. } | Air::TupleAccessor { scope, .. }
| Air::TupleIndex { scope, .. } | Air::TupleIndex { scope, .. }
| Air::TupleClause { scope, .. } => scope.to_vec(), | Air::Todo { scope, .. }
| Air::ErrorTerm { scope, .. }
| Air::Trace { scope, .. } => scope.clone(),
} }
} }
pub fn tipo(&self) -> Option<Arc<Type>> { pub fn tipo(&self) -> Option<Arc<Type>> {
match self { match self {
Air::Int { .. } => Some(
Type::App {
public: true,
module: String::new(),
name: "Int".to_string(),
args: vec![],
}
.into(),
),
Air::String { .. } => Some(
Type::App {
public: true,
module: String::new(),
name: "String".to_string(),
args: vec![],
}
.into(),
),
Air::ByteArray { .. } => Some(
Type::App {
public: true,
module: String::new(),
name: "ByteArray".to_string(),
args: vec![],
}
.into(),
),
Air::Bool { .. } => Some(
Type::App {
public: true,
module: String::new(),
name: "Bool".to_string(),
args: vec![],
}
.into(),
),
Air::Void { .. } => Some(
Type::App {
public: true,
module: String::new(),
name: "Void".to_string(),
args: vec![],
}
.into(),
),
Air::Var { constructor, .. } => Some(constructor.tipo.clone()),
Air::List { tipo, .. } Air::List { tipo, .. }
| Air::ListAccessor { tipo, .. } | Air::Tuple { tipo, .. }
| Air::ListExpose { tipo, .. } | Air::Call { tipo, .. }
| Air::Builtin { tipo, .. } | Air::Builtin { tipo, .. }
| Air::BinOp { tipo, .. } | Air::BinOp { tipo, .. }
| Air::UnWrapData { tipo, .. }
| Air::When { tipo, .. } | Air::When { tipo, .. }
| Air::Clause { tipo, .. } | Air::Clause { tipo, .. }
| Air::ListClause { tipo, .. } | Air::ListClause { tipo, .. }
| Air::TupleClause { tipo, .. } | Air::TupleClause { tipo, .. }
| Air::ClauseGuard { tipo, .. } | Air::ClauseGuard { tipo, .. }
| Air::If { tipo, .. }
| Air::ListClauseGuard { tipo, .. } | Air::ListClauseGuard { tipo, .. }
| Air::Record { tipo, .. } | Air::Record { tipo, .. }
| Air::RecordUpdate { tipo, .. }
| Air::RecordAccess { tipo, .. } | Air::RecordAccess { tipo, .. }
| Air::Tuple { tipo, .. } | Air::ListAccessor { tipo, .. }
| Air::ListExpose { tipo, .. }
| Air::TupleAccessor { tipo, .. }
| Air::TupleIndex { tipo, .. } | Air::TupleIndex { tipo, .. }
| Air::Todo { tipo, .. } | Air::Todo { tipo, .. }
| Air::ErrorTerm { tipo, .. } | Air::ErrorTerm { tipo, .. }
| Air::Trace { tipo, .. } | Air::Trace { tipo, .. } => Some(tipo.clone()),
| Air::TupleAccessor { tipo, .. }
| Air::Var { Air::DefineFunc { .. }
constructor: ValueConstructor { tipo, .. }, | Air::Fn { .. }
.. | Air::Let { .. }
} => Some(tipo.clone()), | Air::WrapClause { .. }
_ => None, | Air::AssertConstr { .. }
| Air::Finally { .. }
| Air::FieldsExpose { .. } => None,
Air::UnOp { op, .. } => match op {
UnOp::Not => Some(
Type::App {
public: true,
module: String::new(),
name: "Bool".to_string(),
args: vec![],
}
.into(),
),
UnOp::Negate => Some(
Type::App {
public: true,
module: String::new(),
name: "Int".to_string(),
args: vec![],
}
.into(),
),
},
} }
} }
} }

View File

@ -1,14 +1,10 @@
use std::{ use std::{cell::RefCell, sync::Arc};
cell::RefCell,
collections::{HashMap, HashSet},
sync::Arc,
};
use indexmap::IndexMap; use indexmap::{IndexMap, IndexSet};
use itertools::Itertools; use itertools::Itertools;
use uplc::{ use uplc::{
ast::{ ast::{
builder::{apply_wrap, if_else}, builder::{apply_wrap, delayed_choose_list, if_else},
Constant as UplcConstant, Name, Term, Type as UplcType, Constant as UplcConstant, Name, Term, Type as UplcType,
}, },
builtins::DefaultFunction, builtins::DefaultFunction,
@ -19,7 +15,7 @@ use uplc::{
use crate::{ use crate::{
air::Air, air::Air,
ast::{ ast::{
BinOp, Clause, ClauseGuard, Constant, DataType, Pattern, Span, TypedArg, TypedDataType, AssignmentKind, BinOp, Clause, ClauseGuard, Constant, DataType, Pattern, Span, TypedArg, TypedDataType,
UnOp, UnOp,
}, },
expr::TypedExpr, expr::TypedExpr,
@ -55,6 +51,12 @@ pub struct FunctionAccessKey {
pub variant_name: String, pub variant_name: String,
} }
#[derive(Clone, Debug)]
pub struct AssignmentProperties {
pub value_is_data: bool,
pub kind: AssignmentKind,
}
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub enum ClauseProperties { pub enum ClauseProperties {
ConstrClause { ConstrClause {
@ -68,14 +70,14 @@ pub enum ClauseProperties {
needs_constr_var: bool, needs_constr_var: bool,
is_complex_clause: bool, is_complex_clause: bool,
original_subject_name: String, original_subject_name: String,
current_index: usize, current_index: i64,
}, },
TupleClause { TupleClause {
clause_var_name: String, clause_var_name: String,
needs_constr_var: bool, needs_constr_var: bool,
is_complex_clause: bool, is_complex_clause: bool,
original_subject_name: String, original_subject_name: String,
defined_tuple_indices: HashSet<(usize, String)>, defined_tuple_indices: IndexSet<(usize, String)>,
}, },
} }
@ -87,7 +89,7 @@ impl ClauseProperties {
needs_constr_var: false, needs_constr_var: false,
is_complex_clause: false, is_complex_clause: false,
original_subject_name: subject_name, original_subject_name: subject_name,
current_index: 0, current_index: -1,
} }
} else if t.is_tuple() { } else if t.is_tuple() {
ClauseProperties::TupleClause { ClauseProperties::TupleClause {
@ -95,7 +97,7 @@ impl ClauseProperties {
needs_constr_var: false, needs_constr_var: false,
is_complex_clause: false, is_complex_clause: false,
original_subject_name: subject_name, original_subject_name: subject_name,
defined_tuple_indices: HashSet::new(), defined_tuple_indices: IndexSet::new(),
} }
} else { } else {
ClauseProperties::ConstrClause { ClauseProperties::ConstrClause {
@ -482,11 +484,13 @@ pub fn list_access_to_uplc(
tail: bool, tail: bool,
current_index: usize, current_index: usize,
term: Term<Name>, term: Term<Name>,
tipo: &Type, tipos: Vec<Arc<Type>>,
check_last_item: bool,
) -> Term<Name> { ) -> Term<Name> {
let (first, names) = names.split_first().unwrap(); if let Some((first, names)) = names.split_first() {
let (current_tipo, tipos) = tipos.split_first().unwrap();
let head_list = if tipo.is_map() { let head_list = if current_tipo.is_map() {
apply_wrap( apply_wrap(
Term::Builtin(DefaultFunction::HeadList).force_wrap(), Term::Builtin(DefaultFunction::HeadList).force_wrap(),
Term::Var(Name { Term::Var(Name {
@ -503,7 +507,7 @@ pub fn list_access_to_uplc(
unique: 0.into(), unique: 0.into(),
}), }),
), ),
&tipo.clone().get_inner_types()[0], &current_tipo.to_owned(),
) )
}; };
@ -556,15 +560,37 @@ pub fn list_access_to_uplc(
text: first.clone(), text: first.clone(),
unique: 0.into(), unique: 0.into(),
}, },
body: term.into(), body: if check_last_item {
}, delayed_choose_list(
apply_wrap( apply_wrap(
Term::Builtin(DefaultFunction::HeadList).force_wrap(), Term::Builtin(DefaultFunction::TailList).force_wrap(),
Term::Var(Name { Term::Var(Name {
text: format!("tail_index_{}_{}", current_index, id_list[current_index]), text: format!(
"tail_index_{}_{}",
current_index, id_list[current_index]
),
unique: 0.into(), unique: 0.into(),
}), }),
), ),
term,
apply_wrap(
apply_wrap(
Term::Builtin(DefaultFunction::Trace).force_wrap(),
Term::Constant(UplcConstant::String(
"List/Tuple contains more items than it should"
.to_string(),
)),
),
Term::Delay(Term::Error.into()),
)
.force_wrap(),
)
.into()
} else {
term.into()
},
},
head_list,
) )
.into(), .into(),
} }
@ -581,7 +607,15 @@ pub fn list_access_to_uplc(
unique: 0.into(), unique: 0.into(),
}, },
body: apply_wrap( body: apply_wrap(
list_access_to_uplc(names, id_list, tail, current_index + 1, term, tipo), list_access_to_uplc(
names,
id_list,
tail,
current_index + 1,
term,
tipos.to_owned(),
check_last_item,
),
apply_wrap( apply_wrap(
Term::Builtin(DefaultFunction::TailList).force_wrap(), Term::Builtin(DefaultFunction::TailList).force_wrap(),
Term::Var(Name { Term::Var(Name {
@ -600,6 +634,9 @@ pub fn list_access_to_uplc(
.into(), .into(),
} }
} }
} else {
term
}
} }
pub fn get_common_ancestor(scope: &[u64], scope_prev: &[u64]) -> Vec<u64> { pub fn get_common_ancestor(scope: &[u64], scope_prev: &[u64]) -> Vec<u64> {
@ -760,7 +797,7 @@ pub fn match_ir_for_recursion(
} }
} }
pub fn find_generics_to_replace(tipo: &mut Arc<Type>, generic_types: &HashMap<u64, Arc<Type>>) { pub fn find_generics_to_replace(tipo: &mut Arc<Type>, generic_types: &IndexMap<u64, Arc<Type>>) {
if let Some(id) = tipo.get_generic() { if let Some(id) = tipo.get_generic() {
//If generic does not have a type we know of like a None in option then just use same type //If generic does not have a type we know of like a None in option then just use same type
*tipo = generic_types.get(&id).unwrap_or(tipo).clone(); *tipo = generic_types.get(&id).unwrap_or(tipo).clone();
@ -986,7 +1023,7 @@ pub fn wrap_validator_args(term: Term<Name>, arguments: Vec<TypedArg>) -> Term<N
pub fn monomorphize( pub fn monomorphize(
ir: Vec<Air>, ir: Vec<Air>,
generic_types: HashMap<u64, Arc<Type>>, generic_types: IndexMap<u64, Arc<Type>>,
full_type: &Arc<Type>, full_type: &Arc<Type>,
) -> (String, Vec<Air>) { ) -> (String, Vec<Air>) {
let mut new_air = ir.clone(); let mut new_air = ir.clone();
@ -1053,6 +1090,7 @@ pub fn monomorphize(
tipo, tipo,
names, names,
tail, tail,
check_last_item,
} => { } => {
if tipo.is_generic() { if tipo.is_generic() {
let mut tipo = tipo.clone(); let mut tipo = tipo.clone();
@ -1063,6 +1101,7 @@ pub fn monomorphize(
names, names,
tipo, tipo,
tail, tail,
check_last_item,
}; };
needs_variant = true; needs_variant = true;
} }
@ -1114,8 +1153,15 @@ pub fn monomorphize(
needs_variant = true; needs_variant = true;
} }
} }
// TODO check on assignment if type is needed Air::UnWrapData { scope, tipo } => {
Air::Assignment { .. } => {} if tipo.is_generic() {
let mut tipo = tipo.clone();
find_generics_to_replace(&mut tipo, &generic_types);
new_air[index] = Air::UnWrapData { scope, tipo };
needs_variant = true;
}
}
Air::When { Air::When {
scope, scope,
tipo, tipo,
@ -1327,8 +1373,8 @@ pub fn monomorphize(
} }
Air::FieldsExpose { Air::FieldsExpose {
scope, scope,
count,
indices, indices,
check_last_item,
} => { } => {
let mut new_indices = vec![]; let mut new_indices = vec![];
for (ind, name, tipo) in indices { for (ind, name, tipo) in indices {
@ -1343,16 +1389,18 @@ pub fn monomorphize(
} }
new_air[index] = Air::FieldsExpose { new_air[index] = Air::FieldsExpose {
scope, scope,
count,
indices: new_indices, indices: new_indices,
check_last_item,
}; };
} }
Air::RecordUpdate { Air::RecordUpdate {
scope, scope,
highest_index, highest_index,
indices, indices,
tipo,
} => { } => {
let mut new_indices = vec![]; let mut new_indices = vec![];
let mut tipo = tipo.clone();
for (ind, tipo) in indices { for (ind, tipo) in indices {
if tipo.is_generic() { if tipo.is_generic() {
let mut tipo = tipo.clone(); let mut tipo = tipo.clone();
@ -1363,18 +1411,51 @@ pub fn monomorphize(
new_indices.push((ind, tipo)); new_indices.push((ind, tipo));
} }
} }
if tipo.is_generic() {
find_generics_to_replace(&mut tipo, &generic_types);
}
new_air[index] = Air::RecordUpdate { new_air[index] = Air::RecordUpdate {
scope, scope,
highest_index, highest_index,
indices: new_indices, indices: new_indices,
tipo,
}; };
} }
Air::TupleAccessor { scope, names, tipo } => { Air::TupleAccessor {
scope,
names,
tipo,
check_last_item,
} => {
if tipo.is_generic() { if tipo.is_generic() {
let mut tipo = tipo.clone(); let mut tipo = tipo.clone();
find_generics_to_replace(&mut tipo, &generic_types); find_generics_to_replace(&mut tipo, &generic_types);
new_air[index] = Air::TupleAccessor { scope, names, tipo }; new_air[index] = Air::TupleAccessor {
scope,
names,
tipo,
check_last_item,
};
needs_variant = true;
}
}
Air::Call { scope, count, tipo } => {
if tipo.is_generic() {
let mut tipo = tipo.clone();
find_generics_to_replace(&mut tipo, &generic_types);
new_air[index] = Air::Call { scope, count, tipo };
needs_variant = true;
}
}
Air::If { scope, tipo } => {
if tipo.is_generic() {
let mut tipo = tipo.clone();
find_generics_to_replace(&mut tipo, &generic_types);
new_air[index] = Air::If { scope, tipo };
needs_variant = true; needs_variant = true;
} }
} }
@ -1393,14 +1474,14 @@ pub fn monomorphize(
(new_name, new_air) (new_name, new_air)
} }
pub fn handle_func_deps_ir( pub fn handle_func_dependencies_ir(
dep_ir: &mut Vec<Air>, dependencies_ir: &mut Vec<Air>,
funt_comp: &FuncComponents, funt_comp: &FuncComponents,
func_components: &IndexMap<FunctionAccessKey, FuncComponents>, func_components: &IndexMap<FunctionAccessKey, FuncComponents>,
defined_functions: &mut HashMap<FunctionAccessKey, ()>, defined_functions: &mut IndexMap<FunctionAccessKey, ()>,
func_index_map: &IndexMap<FunctionAccessKey, Vec<u64>>, func_index_map: &IndexMap<FunctionAccessKey, Vec<u64>>,
func_scope: &[u64], func_scope: &[u64],
to_be_defined: &mut HashMap<FunctionAccessKey, ()>, to_be_defined: &mut IndexMap<FunctionAccessKey, ()>,
) { ) {
let mut funt_comp = funt_comp.clone(); let mut funt_comp = funt_comp.clone();
@ -1451,9 +1532,9 @@ pub fn handle_func_deps_ir(
temp_ir.append(&mut recursion_ir); temp_ir.append(&mut recursion_ir);
temp_ir.append(dep_ir); temp_ir.append(dependencies_ir);
*dep_ir = temp_ir; *dependencies_ir = temp_ir;
if get_common_ancestor(dep_scope, func_scope) == func_scope.to_vec() { if get_common_ancestor(dep_scope, func_scope) == func_scope.to_vec() {
defined_functions.insert(dependency, ()); defined_functions.insert(dependency, ());
} }
@ -1492,10 +1573,11 @@ pub fn handle_recursion_ir(
let current_call = recursion_ir[index - 1].clone(); let current_call = recursion_ir[index - 1].clone();
match current_call { match current_call {
Air::Call { scope, count } => { Air::Call { scope, count, tipo } => {
recursion_ir[index - 1] = Air::Call { recursion_ir[index - 1] = Air::Call {
scope, scope,
count: count + 1, count: count + 1,
tipo,
} }
} }
_ => unreachable!(), _ => unreachable!(),
@ -1504,7 +1586,7 @@ pub fn handle_recursion_ir(
} }
pub fn lookup_data_type_by_tipo( pub fn lookup_data_type_by_tipo(
data_types: HashMap<DataTypeKey, &TypedDataType>, data_types: IndexMap<DataTypeKey, &TypedDataType>,
tipo: &Type, tipo: &Type,
) -> Option<DataType<Arc<Type>>> { ) -> Option<DataType<Arc<Type>>> {
match tipo { match tipo {
@ -1539,7 +1621,7 @@ pub fn lookup_data_type_by_tipo(
pub fn check_replaceable_opaque_type( pub fn check_replaceable_opaque_type(
t: &Arc<Type>, t: &Arc<Type>,
data_types: &HashMap<DataTypeKey, &TypedDataType>, data_types: &IndexMap<DataTypeKey, &TypedDataType>,
) -> bool { ) -> bool {
let data_type = lookup_data_type_by_tipo(data_types.clone(), t); let data_type = lookup_data_type_by_tipo(data_types.clone(), t);
@ -1551,12 +1633,12 @@ pub fn check_replaceable_opaque_type(
} }
} }
pub fn replace_opaque_type(t: &mut Arc<Type>, data_types: HashMap<DataTypeKey, &TypedDataType>) { pub fn replace_opaque_type(t: &mut Arc<Type>, data_types: IndexMap<DataTypeKey, &TypedDataType>) {
if check_replaceable_opaque_type(t, &data_types) && matches!(&**t, Type::App { .. }) { if check_replaceable_opaque_type(t, &data_types) && matches!(&**t, Type::App { .. }) {
let data_type = lookup_data_type_by_tipo(data_types.clone(), t).unwrap(); let data_type = lookup_data_type_by_tipo(data_types.clone(), t).unwrap();
let new_type_fields = data_type.typed_parameters.clone(); let new_type_fields = data_type.typed_parameters.clone();
let mut generics_type_map: HashMap<u64, Arc<Type>> = HashMap::new(); let mut generics_type_map: IndexMap<u64, Arc<Type>> = IndexMap::new();
for (tipo, param) in new_type_fields.iter().zip(t.arg_types().unwrap()) { for (tipo, param) in new_type_fields.iter().zip(t.arg_types().unwrap()) {
let mut map = generics_type_map.into_iter().collect_vec(); let mut map = generics_type_map.into_iter().collect_vec();

View File

@ -52,8 +52,8 @@ pub fn lexer() -> impl Parser<char, Vec<(Token, Span)>, Error = ParseError> {
just('|').to(Token::Vbar), just('|').to(Token::Vbar),
just("&&").to(Token::AmperAmper), just("&&").to(Token::AmperAmper),
just('#').to(Token::Hash), just('#').to(Token::Hash),
just("\n\n").to(Token::EmptyLine), choice((just("\n\n"), just("\r\n\r\n"))).to(Token::EmptyLine),
just("\n").to(Token::NewLine), choice((just("\n"), just("\r\n"))).to(Token::NewLine),
)); ));
let grouping = choice(( let grouping = choice((

View File

@ -22,6 +22,22 @@ fn assert_definitions(code: &str, definitions: Vec<ast::UntypedDefinition>) {
) )
} }
#[test]
fn windows_newline() {
let code = "use aiken/list\r\n";
assert_definitions(
code,
vec![ast::UntypedDefinition::Use(Use {
location: Span::new((), 0..14),
module: vec!["aiken".to_string(), "list".to_string()],
as_name: None,
unqualified: vec![],
package: (),
})],
)
}
#[test] #[test]
fn import() { fn import() {
let code = indoc! {r#" let code = indoc! {r#"

View File

@ -173,6 +173,14 @@ impl Type {
} }
} }
pub fn is_data(&self) -> bool {
match self {
Self::App { module, name, .. } => "Data" == name && module.is_empty(),
Self::Var { tipo } => tipo.borrow().is_data(),
_ => false,
}
}
pub fn is_generic(&self) -> bool { pub fn is_generic(&self) -> bool {
match self { match self {
Type::App { args, .. } => { Type::App { args, .. } => {
@ -205,6 +213,7 @@ 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(),
_ => None, _ => None,
} }
} }
@ -467,6 +476,13 @@ impl TypeVar {
} }
} }
pub fn is_data(&self) -> bool {
match self {
Self::Link { tipo } => tipo.is_data(),
_ => false,
}
}
pub fn is_generic(&self) -> bool { pub fn is_generic(&self) -> bool {
match self { match self {
TypeVar::Generic { .. } => true, TypeVar::Generic { .. } => true,
@ -483,6 +499,13 @@ impl TypeVar {
} }
} }
pub fn arg_types(&self) -> Option<Vec<Arc<Type>>> {
match self {
Self::Link { tipo } => tipo.arg_types(),
_ => None,
}
}
pub fn get_inner_type(&self) -> Vec<Arc<Type>> { pub fn get_inner_type(&self) -> Vec<Arc<Type>> {
match self { match self {
Self::Link { tipo } => tipo.get_inner_types(), Self::Link { tipo } => tipo.get_inner_types(),

View File

@ -1,7 +1,7 @@
use super::Type; use super::Type;
use crate::{ use crate::{
ast::{Annotation, BinOp, CallArg, Span, TodoKind, UntypedPattern}, ast::{Annotation, BinOp, CallArg, Span, TodoKind, UntypedPattern},
expr, expr::{self, UntypedExpr},
format::Formatter, format::Formatter,
levenshtein, levenshtein,
pretty::Documentable, pretty::Documentable,
@ -172,20 +172,7 @@ You can use '{discard}' and numbers to distinguish between similar names.
If you really meant to return that last expression, try to replace it with the following: If you really meant to return that last expression, try to replace it with the following:
{sample}"# {sample}"#
, sample = Formatter::new() , sample = format_suggestion(expr)
.expr(expr)
.to_pretty_string(70)
.lines()
.enumerate()
.map(|(ix, line)| {
if ix == 0 {
format!("╰─▶ {}", line.yellow())
} else {
format!(" {line}").yellow().to_string()
}
})
.collect::<Vec<_>>()
.join("")
))] ))]
LastExpressionIsAssignment { LastExpressionIsAssignment {
#[label("let-binding as last expression")] #[label("let-binding as last expression")]
@ -737,6 +724,15 @@ The best thing to do from here is to remove it."#))]
location: Span, location: Span,
name: String, name: String,
}, },
#[error("I discovered a type cast from Data without an annotation")]
#[diagnostic(code("illegal::type_cast"))]
#[diagnostic(help("Try adding an annotation...\n\n{}", format_suggestion(value)))]
CastDataNoAnn {
#[label]
location: Span,
value: UntypedExpr,
},
} }
impl Error { impl Error {
@ -1034,14 +1030,12 @@ fn suggest_import_constructor() -> String {
#[derive(Debug, PartialEq, Clone, thiserror::Error, Diagnostic)] #[derive(Debug, PartialEq, Clone, thiserror::Error, Diagnostic)]
pub enum Warning { pub enum Warning {
#[error("I found a todo left in the code.\n")] #[error("I found a record update using all fields; thus redundant.\n")]
#[diagnostic(help("You probably want to replace that one with real code... eventually."))] #[diagnostic(url("https://aiken-lang.org/language-tour/custom-types#record-updates"))]
#[diagnostic(code("todo"))] #[diagnostic(code("record_update::all_fields"))]
Todo { AllFieldsRecordUpdate {
kind: TodoKind,
#[label] #[label]
location: Span, location: Span,
tipo: Arc<Type>,
}, },
#[error( #[error(
@ -1056,9 +1050,10 @@ pub enum Warning {
location: Span, location: Span,
}, },
#[error("I found a literal that is unused.\n")] #[error("I found a record update with no fields; effectively updating nothing.\n")]
#[diagnostic(code("unused::literal"))] #[diagnostic(url("https://aiken-lang.org/language-tour/custom-types#record-updates"))]
UnusedLiteral { #[diagnostic(code("record_update::no_fields"))]
NoFieldsRecordUpdate {
#[label] #[label]
location: Span, location: Span,
}, },
@ -1070,29 +1065,25 @@ pub enum Warning {
location: Span, location: Span,
}, },
#[error("I found a record update with no fields; effectively updating nothing.\n")] #[error("I found a when expression with a single clause.")]
#[diagnostic(url("https://aiken-lang.org/language-tour/custom-types#record-updates"))] #[diagnostic(
#[diagnostic(code("record_update::no_fields"))] code("single_when_clause"),
NoFieldsRecordUpdate { help("Prefer using a {} binding like so...\n\n{}", "let".purple(), format_suggestion(sample))
#[label] )]
SingleWhenClause {
#[label("use let")]
location: Span, location: Span,
sample: UntypedExpr,
}, },
#[error("I found a record update using all fields; thus redundant.\n")] #[error("I found a todo left in the code.\n")]
#[diagnostic(url("https://aiken-lang.org/language-tour/custom-types#record-updates"))] #[diagnostic(help("You probably want to replace that one with real code... eventually."))]
#[diagnostic(code("record_update::all_fields"))] #[diagnostic(code("todo"))]
AllFieldsRecordUpdate { Todo {
kind: TodoKind,
#[label] #[label]
location: Span, location: Span,
}, tipo: Arc<Type>,
#[error("I discovered an unused type: '{}'.\n", name.purple())]
#[diagnostic(code("unused::type"))]
UnusedType {
#[label]
location: Span,
imported: bool,
name: String,
}, },
#[error("I discovered an unused constructor: '{}'.\n", name.purple())] #[error("I discovered an unused constructor: '{}'.\n", name.purple())]
@ -1107,6 +1098,17 @@ pub enum Warning {
name: String, name: String,
}, },
#[error("I discovered an unused imported module: '{}'.\n", name.purple())]
#[diagnostic(help(
"No big deal, but you might want to remove it to get rid of that warning."
))]
#[diagnostic(code("unused::import::module"))]
UnusedImportedModule {
#[label]
location: Span,
name: String,
},
#[error("I discovered an unused imported value: '{}'.\n", name.purple())] #[error("I discovered an unused imported value: '{}'.\n", name.purple())]
#[diagnostic(help( #[diagnostic(help(
"No big deal, but you might want to remove it to get rid of that warning." "No big deal, but you might want to remove it to get rid of that warning."
@ -1118,12 +1120,21 @@ pub enum Warning {
name: String, name: String,
}, },
#[error("I discovered an unused imported module: '{}'.\n", name.purple())] #[error("I found a literal that is unused.\n")]
#[diagnostic(code("unused::literal"))]
UnusedLiteral {
#[label]
location: Span,
},
#[error("I found an unused private function: '{}'.\n", name.purple())]
#[diagnostic(help( #[diagnostic(help(
"No big deal, but you might want to remove it to get rid of that warning." "Perhaps your forgot to make it public using the '{keyword_pub}' keyword?\n\
Otherwise, you might want to get rid of it altogether."
, keyword_pub = "pub".bright_blue()
))] ))]
#[diagnostic(code("unused::import::module"))] #[diagnostic(code("unused::function"))]
UnusedImportedModule { UnusedPrivateFunction {
#[label] #[label]
location: Span, location: Span,
name: String, name: String,
@ -1142,16 +1153,12 @@ pub enum Warning {
name: String, name: String,
}, },
#[error("I found an unused private function: '{}'.\n", name.purple())] #[error("I discovered an unused type: '{}'.\n", name.purple())]
#[diagnostic(help( #[diagnostic(code("unused::type"))]
"Perhaps your forgot to make it public using the '{keyword_pub}' keyword?\n\ UnusedType {
Otherwise, you might want to get rid of it altogether."
, keyword_pub = "pub".bright_blue()
))]
#[diagnostic(code("unused::function"))]
UnusedPrivateFunction {
#[label] #[label]
location: Span, location: Span,
imported: bool,
name: String, name: String,
}, },
@ -1187,3 +1194,20 @@ pub enum UnknownRecordFieldSituation {
/// This unknown record field is being called as a function. i.e. `record.field()` /// This unknown record field is being called as a function. i.e. `record.field()`
FunctionCall, FunctionCall,
} }
fn format_suggestion(sample: &UntypedExpr) -> String {
Formatter::new()
.expr(sample)
.to_pretty_string(70)
.lines()
.enumerate()
.map(|(ix, line)| {
if ix == 0 {
format!("╰─▶ {}", line.yellow())
} else {
format!(" {line}").yellow().to_string()
}
})
.collect::<Vec<_>>()
.join("")
}

View File

@ -807,8 +807,8 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
annotation: &Option<Annotation>, annotation: &Option<Annotation>,
location: Span, location: Span,
) -> Result<TypedExpr, Error> { ) -> Result<TypedExpr, Error> {
let value = self.in_new_scope(|value_typer| value_typer.infer(value))?; let typed_value = self.in_new_scope(|value_typer| value_typer.infer(value.clone()))?;
let mut value_typ = value.tipo(); let mut value_typ = typed_value.tipo();
// Check that any type annotation is accurate. // Check that any type annotation is accurate.
let pattern = if let Some(ann) = annotation { let pattern = if let Some(ann) = annotation {
@ -819,7 +819,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
self.unify( self.unify(
ann_typ.clone(), ann_typ.clone(),
value_typ.clone(), value_typ.clone(),
value.type_defining_location(), typed_value.type_defining_location(),
)?; )?;
value_typ = ann_typ.clone(); value_typ = ann_typ.clone();
@ -831,6 +831,24 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
Some(ann_typ), Some(ann_typ),
)? )?
} else { } else {
if value_typ.is_data() {
return Err(Error::CastDataNoAnn {
location,
value: UntypedExpr::Assignment {
location,
value: value.into(),
pattern,
kind,
annotation: Some(Annotation::Constructor {
location: Span::empty(),
module: None,
name: "Type".to_string(),
arguments: vec![],
}),
},
});
}
// Ensure the pattern matches the type of the value // Ensure the pattern matches the type of the value
PatternTyper::new(self.environment, &self.hydrator).unify( PatternTyper::new(self.environment, &self.hydrator).unify(
pattern, pattern,
@ -860,7 +878,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
tipo: value_typ, tipo: value_typ,
kind, kind,
pattern, pattern,
value: Box::new(value), value: Box::new(typed_value),
}) })
} }
@ -1906,6 +1924,21 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
clauses: Vec<UntypedClause>, clauses: Vec<UntypedClause>,
location: Span, location: Span,
) -> Result<TypedExpr, Error> { ) -> Result<TypedExpr, Error> {
// if there is only one clause we want to present a warning
// that suggests that a `let` binding should be used instead.
if clauses.len() == 1 {
self.environment.warnings.push(Warning::SingleWhenClause {
location: clauses[0].pattern[0].location(),
sample: UntypedExpr::Assignment {
location: Span::empty(),
value: Box::new(subjects[0].clone()),
pattern: clauses[0].pattern[0].clone(),
kind: AssignmentKind::Let,
annotation: None,
},
});
}
let subjects_count = subjects.len(); let subjects_count = subjects.len();
let mut typed_subjects = Vec::with_capacity(subjects_count); let mut typed_subjects = Vec::with_capacity(subjects_count);

File diff suppressed because it is too large Load Diff

View File

@ -16,6 +16,7 @@ fslock = "0.2.1"
futures = "0.3.25" futures = "0.3.25"
hex = "0.4.3" hex = "0.4.3"
ignore = "0.4.18" ignore = "0.4.18"
indexmap = "1.9.1"
itertools = "0.10.1" itertools = "0.10.1"
miette = { version = "5.3.0", features = ["fancy"] } miette = { version = "5.3.0", features = ["fancy"] }
owo-colors = "3.5.0" owo-colors = "3.5.0"

View File

@ -20,6 +20,7 @@ use aiken_lang::{
IdGenerator, MINT, PUBLISH, SPEND, VALIDATOR_NAMES, WITHDRAW, IdGenerator, MINT, PUBLISH, SPEND, VALIDATOR_NAMES, WITHDRAW,
}; };
use deps::UseManifest; use deps::UseManifest;
use indexmap::IndexMap;
use miette::NamedSource; use miette::NamedSource;
use options::{CodeGenMode, Options}; use options::{CodeGenMode, Options};
use package_name::PackageName; use package_name::PackageName;
@ -482,9 +483,9 @@ where
validators: Vec<(PathBuf, String, TypedFunction)>, validators: Vec<(PathBuf, String, TypedFunction)>,
) -> Result<Vec<Script>, Error> { ) -> Result<Vec<Script>, Error> {
let mut programs = Vec::new(); let mut programs = Vec::new();
let mut functions = HashMap::new(); let mut functions = IndexMap::new();
let mut type_aliases = HashMap::new(); let mut type_aliases = IndexMap::new();
let mut data_types = HashMap::new(); let mut data_types = IndexMap::new();
let prelude_functions = builtins::prelude_functions(&self.id_gen); let prelude_functions = builtins::prelude_functions(&self.id_gen);
for (access_key, func) in prelude_functions.iter() { for (access_key, func) in prelude_functions.iter() {
@ -539,11 +540,15 @@ where
.. ..
} = func_def; } = func_def;
let mut modules_map = IndexMap::new();
modules_map.extend(self.module_types.clone());
let mut generator = CodeGenerator::new( let mut generator = CodeGenerator::new(
&functions, &functions,
// &type_aliases, // &type_aliases,
&data_types, &data_types,
&self.module_types, &modules_map,
); );
self.event_listener.handle_event(Event::GeneratingUPLC { self.event_listener.handle_event(Event::GeneratingUPLC {
@ -573,9 +578,9 @@ where
should_collect: fn(&TypedDefinition) -> bool, should_collect: fn(&TypedDefinition) -> bool,
) -> Result<Vec<Script>, Error> { ) -> Result<Vec<Script>, Error> {
let mut programs = Vec::new(); let mut programs = Vec::new();
let mut functions = HashMap::new(); let mut functions = IndexMap::new();
let mut type_aliases = HashMap::new(); let mut type_aliases = IndexMap::new();
let mut data_types = HashMap::new(); let mut data_types = IndexMap::new();
let prelude_functions = builtins::prelude_functions(&self.id_gen); let prelude_functions = builtins::prelude_functions(&self.id_gen);
for (access_key, func) in prelude_functions.iter() { for (access_key, func) in prelude_functions.iter() {
@ -648,21 +653,25 @@ where
}) })
} }
let mut modules_map = IndexMap::new();
modules_map.extend(self.module_types.clone());
let mut generator = CodeGenerator::new( let mut generator = CodeGenerator::new(
&functions, &functions,
// &type_aliases, // &type_aliases,
&data_types, &data_types,
&self.module_types, &modules_map,
); );
let evaluation_hint = if let Some((bin_op, left_src, right_src)) = func_def.test_hint() let evaluation_hint = if let Some((bin_op, left_src, right_src)) = func_def.test_hint()
{ {
let left = CodeGenerator::new(&functions, &data_types, &self.module_types) let left = CodeGenerator::new(&functions, &data_types, &modules_map)
.generate(*left_src, vec![], false) .generate(*left_src, vec![], false)
.try_into() .try_into()
.unwrap(); .unwrap();
let right = CodeGenerator::new(&functions, &data_types, &self.module_types) let right = CodeGenerator::new(&functions, &data_types, &modules_map)
.generate(*right_src, vec![], false) .generate(*right_src, vec![], false)
.try_into() .try_into()
.unwrap(); .unwrap();

View File

@ -5,6 +5,7 @@ use super::{Constant, Name, Term};
pub const CONSTR_FIELDS_EXPOSER: &str = "__constr_fields_exposer"; pub const CONSTR_FIELDS_EXPOSER: &str = "__constr_fields_exposer";
pub const CONSTR_INDEX_EXPOSER: &str = "__constr_index_exposer"; pub const CONSTR_INDEX_EXPOSER: &str = "__constr_index_exposer";
pub const CONSTR_GET_FIELD: &str = "__constr_get_field"; pub const CONSTR_GET_FIELD: &str = "__constr_get_field";
pub const ASSERT_ON_LIST: &str = "__assert_on_list";
pub fn apply_wrap(function: Term<Name>, arg: Term<Name>) -> Term<Name> { pub fn apply_wrap(function: Term<Name>, arg: Term<Name>) -> Term<Name> {
Term::Apply { Term::Apply {
@ -31,6 +32,108 @@ pub fn final_wrapper(term: Term<Name>) -> Term<Name> {
) )
} }
pub fn assert_on_list(term: Term<Name>) -> Term<Name> {
apply_wrap(
Term::Lambda {
parameter_name: Name {
text: ASSERT_ON_LIST.to_string(),
unique: 0.into(),
},
body: apply_wrap(
Term::Lambda {
parameter_name: Name {
text: ASSERT_ON_LIST.to_string(),
unique: 0.into(),
},
body: term.into(),
},
apply_wrap(
Term::Var(Name {
text: ASSERT_ON_LIST.to_string(),
unique: 0.into(),
}),
Term::Var(Name {
text: ASSERT_ON_LIST.to_string(),
unique: 0.into(),
}),
),
)
.into(),
},
Term::Lambda {
parameter_name: Name {
text: ASSERT_ON_LIST.to_string(),
unique: 0.into(),
},
body: Term::Lambda {
parameter_name: Name {
text: "list_to_check".to_string(),
unique: 0.into(),
},
body: Term::Lambda {
parameter_name: Name {
text: "check_with".to_string(),
unique: 0.into(),
},
body: delayed_choose_list(
Term::Var(Name {
text: "list_to_check".to_string(),
unique: 0.into(),
}),
Term::Constant(Constant::Unit),
apply_wrap(
apply_wrap(
Term::Builtin(DefaultFunction::ChooseUnit).force_wrap(),
apply_wrap(
Term::Var(Name {
text: "check_with".to_string(),
unique: 0.into(),
}),
apply_wrap(
Term::Builtin(DefaultFunction::HeadList).force_wrap(),
Term::Var(Name {
text: "list_to_check".to_string(),
unique: 0.into(),
}),
),
),
),
apply_wrap(
apply_wrap(
apply_wrap(
Term::Var(Name {
text: ASSERT_ON_LIST.to_string(),
unique: 0.into(),
}),
Term::Var(Name {
text: ASSERT_ON_LIST.to_string(),
unique: 0.into(),
}),
),
apply_wrap(
Term::Builtin(DefaultFunction::TailList).force_wrap(),
Term::Var(Name {
text: "list_to_check".to_string(),
unique: 0.into(),
}),
),
),
Term::Var(Name {
text: "check_with".to_string(),
unique: 0.into(),
}),
),
),
)
.into(),
}
.into(),
}
.into(),
},
)
}
pub fn constr_fields_exposer(term: Term<Name>) -> Term<Name> { pub fn constr_fields_exposer(term: Term<Name>) -> Term<Name> {
Term::Apply { Term::Apply {
function: Term::Lambda { function: Term::Lambda {

View File

@ -343,7 +343,7 @@ impl Machine {
Err(Error::UnexpectedBuiltinTermArgument(t.as_ref().clone())) Err(Error::UnexpectedBuiltinTermArgument(t.as_ref().clone()))
} }
} }
rest => Err(Error::NonFunctionalApplication(rest)), rest => Err(Error::NonFunctionalApplication(rest, argument)),
} }
} }

View File

@ -16,8 +16,8 @@ pub enum Error {
EvaluationFailure, EvaluationFailure,
#[error("Attempted to instantiate a non-polymorphic term:\n\n{0:#?}")] #[error("Attempted to instantiate a non-polymorphic term:\n\n{0:#?}")]
NonPolymorphicInstantiation(Value), NonPolymorphicInstantiation(Value),
#[error("Attempted to apply a non-function:\n\n{0:#?}")] #[error("Attempted to apply a non-function:\n\n{0:#?} to argument:\n\n{1:#?}")]
NonFunctionalApplication(Value), NonFunctionalApplication(Value, Value),
#[error("Type mismatch expected '{0}' got '{1}'")] #[error("Type mismatch expected '{0}' got '{1}'")]
TypeMismatch(Type, Type), TypeMismatch(Type, Type),
#[error("Type mismatch expected '(list a)' got '{0}'")] #[error("Type mismatch expected '(list a)' got '{0}'")]

View File

@ -1 +1 @@
addr1w9zyujfu4a23cltkm7xe2usj7wedtvqnsk9ecg2zwt6a90s83wahe addr1w8ehrka3eyh8hqxt647qm56z0ju3x8fsyjv2f3cwp5kr5ssvegjnw

View File

@ -1,5 +1,5 @@
{ {
"type": "PlutusScriptV2", "type": "PlutusScriptV2",
"description": "Generated by Aiken", "description": "Generated by Aiken",
"cborHex": "59015159014e01000022253335734646464646466002006464646464646464646600201291010500000000000022323232300c00130050013300500100237566601c601e00490011192999aab9f00114a2294000488c8c8cc0140052f5bded8c06600a002004004446464a666ae68cdc3800a40042006264640026eacd5d080098070011aab9d37540020044466006004002600200244464a666aae7c0044cdd2a400497ae01323232325333573466e3c0180044cdd2a400066ae80dd300125eb804ccc02002000c018dd71aab9d00337566aae78008d5d10011aba100100223335734002941289800800911192999aab9f00114a026464a666ae68c01000852889998030030008021aba2002357420020046eb0cc004c008cc004c00800d20004801088c8ccc00400520000032223333573466e1c0100095d0919980200219b8000348008d5d100080091aab9e37540022930b1" "cborHex": "59015159014e01000022253335734646464646466002006464646464646464646600201291010500000000000022323232300600130060013300600100237566601c601e00490011199ab9a0014a09448c94ccd55cf8008a5114a00024464646600a00297adef6c60330050010020022232325333573466e1c005200210031323200137566ae84004c034008d55ce9baa001002223300300200130010012223253335573e002266e9520024bd700991919192999ab9a3371e00c002266e9520003357406e980092f5c0266601001000600c6eb8d55ce8019bab35573c0046ae88008d5d08008011800800911192999aab9f00114a026464a666ae68c01000852889998030030008021aba2002357420020046eb0cc004c008cc004c00800d20004801088c8ccc00400520000032223333573466e1c0100095d0919980200219b8000348008d5d100080091aab9e37540022930b1"
} }

View File

@ -1 +1 @@
59014e01000022253335734646464646466002006464646464646464646600201291010500000000000022323232300c00130050013300500100237566601c601e00490011192999aab9f00114a2294000488c8c8cc0140052f5bded8c06600a002004004446464a666ae68cdc3800a40042006264640026eacd5d080098070011aab9d37540020044466006004002600200244464a666aae7c0044cdd2a400497ae01323232325333573466e3c0180044cdd2a400066ae80dd300125eb804ccc02002000c018dd71aab9d00337566aae78008d5d10011aba100100223335734002941289800800911192999aab9f00114a026464a666ae68c01000852889998030030008021aba2002357420020046eb0cc004c008cc004c00800d20004801088c8ccc00400520000032223333573466e1c0100095d0919980200219b8000348008d5d100080091aab9e37540022930b1 59014e01000022253335734646464646466002006464646464646464646600201291010500000000000022323232300600130060013300600100237566601c601e00490011199ab9a0014a09448c94ccd55cf8008a5114a00024464646600a00297adef6c60330050010020022232325333573466e1c005200210031323200137566ae84004c034008d55ce9baa001002223300300200130010012223253335573e002266e9520024bd700991919192999ab9a3371e00c002266e9520003357406e980092f5c0266601001000600c6eb8d55ce8019bab35573c0046ae88008d5d08008011800800911192999aab9f00114a026464a666ae68c01000852889998030030008021aba2002357420020046eb0cc004c008cc004c00800d20004801088c8ccc00400520000032223333573466e1c0100095d0919980200219b8000348008d5d100080091aab9e37540022930b1

View File

@ -1 +1 @@
addr_test1wpzyujfu4a23cltkm7xe2usj7wedtvqnsk9ecg2zwt6a90sue6pcu addr_test1wrehrka3eyh8hqxt647qm56z0ju3x8fsyjv2f3cwp5kr5ssh3uwut

View File

@ -1,3 +1,9 @@
pub type Door{
angle: Int,
locked: Bool
}
pub type Car { pub type Car {
Honda { remote_connect: ByteArray, owner: ByteArray, wheels: Int } Honda { remote_connect: ByteArray, owner: ByteArray, wheels: Int }
Ford { Ford {
@ -5,18 +11,19 @@ pub type Car {
owner: ByteArray, owner: ByteArray,
wheels: Int, wheels: Int,
truck_bed_limit: Int, truck_bed_limit: Int,
car_doors: List<Door>
} }
} }
// test update_owner2_should_fail(){ // test update_owner2_should_fail(){
// let initial_car: Data = Ford{remote_connect: #[], owner: #[], wheels: 4, truck_bed_limit: 10000} // let initial_car: Data = Ford{remote_connect: #[], owner: #[], wheels: 4, truck_bed_limit: 10000, car_doors: []}
// assert Honda{ owner, ..} = initial_car // assert Honda{ owner, ..}: Car = initial_car
// owner == #[] // owner == #[]
// } // }
test update_owner1() { test update_owner1() {
let initial_car: Data = let initial_car: Data =
Ford { remote_connect: #[], owner: #[], wheels: 4, truck_bed_limit: 10000 } Ford { remote_connect: #[], owner: #[], wheels: 4, truck_bed_limit: 10000, car_doors: [] }
assert Ford { owner, .. } = initial_car assert Ford { owner, .. }: Car = initial_car
owner == #[] owner == #[]
} }

View File

@ -0,0 +1,5 @@
# This file was generated by Aiken
# You typically do not need to edit this file
requirements = []
packages = []

View File

@ -0,0 +1,3 @@
name = 'aiken-lang/acceptance_test_046'
version = '0.0.0'
description = ''

View File

@ -0,0 +1,9 @@
test sort_by_1() {
let xs = [[4, 3, 2, 1], [2, 3, 4, 5]]
when xs is {
[[], ys] -> False
[xs, []] -> False
[[x, ..xs2], [y, ..ys2]] -> True
_ -> False
}
}

View File

@ -0,0 +1,9 @@
fn when_tuple(a: (Int, Int)) -> Int {
when a is {
(a, b) -> a
}
}
pub fn spend(a, b, c) -> Bool {
when_tuple((4, 1)) == 4
}