Merge branch 'main' into when-clause-guards
This commit is contained in:
commit
b653714c0c
|
@ -117,6 +117,7 @@ dependencies = [
|
|||
"futures",
|
||||
"hex",
|
||||
"ignore",
|
||||
"indexmap",
|
||||
"itertools",
|
||||
"miette",
|
||||
"owo-colors",
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use std::{collections::HashSet, sync::Arc};
|
||||
use std::sync::Arc;
|
||||
|
||||
use indexmap::IndexSet;
|
||||
use uplc::builtins::DefaultFunction;
|
||||
|
||||
use crate::{
|
||||
|
@ -9,6 +10,7 @@ use crate::{
|
|||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Air {
|
||||
// Primitives
|
||||
Int {
|
||||
scope: Vec<u64>,
|
||||
value: String,
|
||||
|
@ -29,17 +31,6 @@ pub enum Air {
|
|||
value: bool,
|
||||
},
|
||||
|
||||
Var {
|
||||
scope: Vec<u64>,
|
||||
constructor: ValueConstructor,
|
||||
name: String,
|
||||
variant_name: String,
|
||||
},
|
||||
|
||||
Fn {
|
||||
scope: Vec<u64>,
|
||||
params: Vec<String>,
|
||||
},
|
||||
List {
|
||||
scope: Vec<u64>,
|
||||
count: usize,
|
||||
|
@ -47,48 +38,30 @@ pub enum Air {
|
|||
tail: bool,
|
||||
},
|
||||
|
||||
ListAccessor {
|
||||
Tuple {
|
||||
scope: Vec<u64>,
|
||||
tipo: Arc<Type>,
|
||||
names: Vec<String>,
|
||||
tail: bool,
|
||||
count: usize,
|
||||
},
|
||||
|
||||
ListExpose {
|
||||
Void {
|
||||
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 {
|
||||
scope: Vec<u64>,
|
||||
count: usize,
|
||||
},
|
||||
|
||||
Builtin {
|
||||
scope: Vec<u64>,
|
||||
func: DefaultFunction,
|
||||
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 {
|
||||
scope: Vec<u64>,
|
||||
func_name: String,
|
||||
|
@ -98,11 +71,47 @@ pub enum Air {
|
|||
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>,
|
||||
name: String,
|
||||
},
|
||||
|
||||
UnWrapData {
|
||||
scope: Vec<u64>,
|
||||
tipo: Arc<Type>,
|
||||
},
|
||||
|
||||
AssertConstr {
|
||||
scope: Vec<u64>,
|
||||
constr_index: usize,
|
||||
},
|
||||
|
||||
// When
|
||||
When {
|
||||
scope: Vec<u64>,
|
||||
tipo: Arc<Type>,
|
||||
|
@ -124,11 +133,15 @@ pub enum Air {
|
|||
complex_clause: bool,
|
||||
},
|
||||
|
||||
WrapClause {
|
||||
scope: Vec<u64>,
|
||||
},
|
||||
|
||||
TupleClause {
|
||||
scope: Vec<u64>,
|
||||
tipo: Arc<Type>,
|
||||
indices: HashSet<(usize, String)>,
|
||||
predefined_indices: HashSet<(usize, String)>,
|
||||
indices: IndexSet<(usize, String)>,
|
||||
predefined_indices: IndexSet<(usize, String)>,
|
||||
subject_name: String,
|
||||
count: usize,
|
||||
complex_clause: bool,
|
||||
|
@ -148,18 +161,17 @@ pub enum Air {
|
|||
inverse: bool,
|
||||
},
|
||||
|
||||
Discard {
|
||||
scope: Vec<u64>,
|
||||
},
|
||||
|
||||
Finally {
|
||||
scope: Vec<u64>,
|
||||
},
|
||||
|
||||
// If
|
||||
If {
|
||||
scope: Vec<u64>,
|
||||
tipo: Arc<Type>,
|
||||
},
|
||||
|
||||
// Record Creation
|
||||
Record {
|
||||
scope: Vec<u64>,
|
||||
constr_index: usize,
|
||||
|
@ -167,6 +179,14 @@ pub enum Air {
|
|||
count: usize,
|
||||
},
|
||||
|
||||
RecordUpdate {
|
||||
scope: Vec<u64>,
|
||||
highest_index: usize,
|
||||
indices: Vec<(usize, Arc<Type>)>,
|
||||
tipo: Arc<Type>,
|
||||
},
|
||||
|
||||
// Field Access
|
||||
RecordAccess {
|
||||
scope: Vec<u64>,
|
||||
record_index: u64,
|
||||
|
@ -175,14 +195,32 @@ pub enum Air {
|
|||
|
||||
FieldsExpose {
|
||||
scope: Vec<u64>,
|
||||
count: usize,
|
||||
indices: Vec<(usize, String, Arc<Type>)>,
|
||||
check_last_item: bool,
|
||||
},
|
||||
|
||||
Tuple {
|
||||
// ListAccess
|
||||
ListAccessor {
|
||||
scope: Vec<u64>,
|
||||
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 {
|
||||
|
@ -191,6 +229,7 @@ pub enum Air {
|
|||
tuple_index: usize,
|
||||
},
|
||||
|
||||
// Misc.
|
||||
Todo {
|
||||
scope: Vec<u64>,
|
||||
label: Option<String>,
|
||||
|
@ -208,23 +247,6 @@ pub enum Air {
|
|||
text: Option<String>,
|
||||
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 {
|
||||
|
@ -234,67 +256,142 @@ impl Air {
|
|||
| Air::String { scope, .. }
|
||||
| Air::ByteArray { scope, .. }
|
||||
| Air::Bool { scope, .. }
|
||||
| Air::Var { scope, .. }
|
||||
| Air::List { scope, .. }
|
||||
| Air::ListAccessor { scope, .. }
|
||||
| Air::ListExpose { scope, .. }
|
||||
| Air::Fn { scope, .. }
|
||||
| Air::Tuple { scope, .. }
|
||||
| Air::Void { scope }
|
||||
| Air::Var { scope, .. }
|
||||
| Air::Call { scope, .. }
|
||||
| Air::DefineFunc { scope, .. }
|
||||
| Air::Fn { scope, .. }
|
||||
| Air::Builtin { scope, .. }
|
||||
| Air::BinOp { scope, .. }
|
||||
| Air::Assignment { scope, .. }
|
||||
| Air::Assert { scope, .. }
|
||||
| Air::DefineFunc { scope, .. }
|
||||
| Air::Lam { scope, .. }
|
||||
| Air::UnOp { scope, .. }
|
||||
| Air::Let { scope, .. }
|
||||
| Air::UnWrapData { scope, .. }
|
||||
| Air::AssertConstr { scope, .. }
|
||||
| Air::When { scope, .. }
|
||||
| Air::Clause { scope, .. }
|
||||
| Air::ListClause { scope, .. }
|
||||
| Air::WrapClause { scope }
|
||||
| Air::TupleClause { scope, .. }
|
||||
| Air::ClauseGuard { scope, .. }
|
||||
| Air::ListClauseGuard { scope, .. }
|
||||
| Air::Discard { scope }
|
||||
| Air::Finally { scope }
|
||||
| Air::If { scope, .. }
|
||||
| Air::Record { scope, .. }
|
||||
| Air::RecordUpdate { scope, .. }
|
||||
| Air::RecordAccess { scope, .. }
|
||||
| Air::FieldsExpose { scope, .. }
|
||||
| Air::Tuple { scope, .. }
|
||||
| Air::Todo { scope, .. }
|
||||
| Air::ErrorTerm { scope, .. }
|
||||
| Air::RecordUpdate { scope, .. }
|
||||
| Air::UnOp { scope, .. }
|
||||
| Air::Trace { scope, .. }
|
||||
| Air::ListAccessor { scope, .. }
|
||||
| Air::ListExpose { scope, .. }
|
||||
| Air::TupleAccessor { 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>> {
|
||||
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::ListAccessor { tipo, .. }
|
||||
| Air::ListExpose { tipo, .. }
|
||||
| Air::Tuple { tipo, .. }
|
||||
| Air::Call { tipo, .. }
|
||||
| Air::Builtin { tipo, .. }
|
||||
| Air::BinOp { tipo, .. }
|
||||
| Air::UnWrapData { tipo, .. }
|
||||
| Air::When { tipo, .. }
|
||||
| Air::Clause { tipo, .. }
|
||||
| Air::ListClause { tipo, .. }
|
||||
| Air::TupleClause { tipo, .. }
|
||||
| Air::ClauseGuard { tipo, .. }
|
||||
| Air::If { tipo, .. }
|
||||
| Air::ListClauseGuard { tipo, .. }
|
||||
| Air::Record { tipo, .. }
|
||||
| Air::RecordUpdate { tipo, .. }
|
||||
| Air::RecordAccess { tipo, .. }
|
||||
| Air::Tuple { tipo, .. }
|
||||
| Air::ListAccessor { tipo, .. }
|
||||
| Air::ListExpose { tipo, .. }
|
||||
| Air::TupleAccessor { tipo, .. }
|
||||
| Air::TupleIndex { tipo, .. }
|
||||
| Air::Todo { tipo, .. }
|
||||
| Air::ErrorTerm { tipo, .. }
|
||||
| Air::Trace { tipo, .. }
|
||||
| Air::TupleAccessor { tipo, .. }
|
||||
| Air::Var {
|
||||
constructor: ValueConstructor { tipo, .. },
|
||||
..
|
||||
} => Some(tipo.clone()),
|
||||
_ => None,
|
||||
| Air::Trace { tipo, .. } => Some(tipo.clone()),
|
||||
|
||||
Air::DefineFunc { .. }
|
||||
| Air::Fn { .. }
|
||||
| Air::Let { .. }
|
||||
| Air::WrapClause { .. }
|
||||
| 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(),
|
||||
),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,14 +1,10 @@
|
|||
use std::{
|
||||
cell::RefCell,
|
||||
collections::{HashMap, HashSet},
|
||||
sync::Arc,
|
||||
};
|
||||
use std::{cell::RefCell, sync::Arc};
|
||||
|
||||
use indexmap::IndexMap;
|
||||
use indexmap::{IndexMap, IndexSet};
|
||||
use itertools::Itertools;
|
||||
use uplc::{
|
||||
ast::{
|
||||
builder::{apply_wrap, if_else},
|
||||
builder::{apply_wrap, delayed_choose_list, if_else},
|
||||
Constant as UplcConstant, Name, Term, Type as UplcType,
|
||||
},
|
||||
builtins::DefaultFunction,
|
||||
|
@ -19,7 +15,7 @@ use uplc::{
|
|||
use crate::{
|
||||
air::Air,
|
||||
ast::{
|
||||
BinOp, Clause, ClauseGuard, Constant, DataType, Pattern, Span, TypedArg, TypedDataType,
|
||||
AssignmentKind, BinOp, Clause, ClauseGuard, Constant, DataType, Pattern, Span, TypedArg, TypedDataType,
|
||||
UnOp,
|
||||
},
|
||||
expr::TypedExpr,
|
||||
|
@ -55,6 +51,12 @@ pub struct FunctionAccessKey {
|
|||
pub variant_name: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct AssignmentProperties {
|
||||
pub value_is_data: bool,
|
||||
pub kind: AssignmentKind,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum ClauseProperties {
|
||||
ConstrClause {
|
||||
|
@ -68,14 +70,14 @@ pub enum ClauseProperties {
|
|||
needs_constr_var: bool,
|
||||
is_complex_clause: bool,
|
||||
original_subject_name: String,
|
||||
current_index: usize,
|
||||
current_index: i64,
|
||||
},
|
||||
TupleClause {
|
||||
clause_var_name: String,
|
||||
needs_constr_var: bool,
|
||||
is_complex_clause: bool,
|
||||
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,
|
||||
is_complex_clause: false,
|
||||
original_subject_name: subject_name,
|
||||
current_index: 0,
|
||||
current_index: -1,
|
||||
}
|
||||
} else if t.is_tuple() {
|
||||
ClauseProperties::TupleClause {
|
||||
|
@ -95,7 +97,7 @@ impl ClauseProperties {
|
|||
needs_constr_var: false,
|
||||
is_complex_clause: false,
|
||||
original_subject_name: subject_name,
|
||||
defined_tuple_indices: HashSet::new(),
|
||||
defined_tuple_indices: IndexSet::new(),
|
||||
}
|
||||
} else {
|
||||
ClauseProperties::ConstrClause {
|
||||
|
@ -482,82 +484,22 @@ pub fn list_access_to_uplc(
|
|||
tail: bool,
|
||||
current_index: usize,
|
||||
term: Term<Name>,
|
||||
tipo: &Type,
|
||||
tipos: Vec<Arc<Type>>,
|
||||
check_last_item: bool,
|
||||
) -> 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() {
|
||||
apply_wrap(
|
||||
Term::Builtin(DefaultFunction::HeadList).force_wrap(),
|
||||
Term::Var(Name {
|
||||
text: format!("tail_index_{}_{}", current_index, id_list[current_index]),
|
||||
unique: 0.into(),
|
||||
}),
|
||||
)
|
||||
} else {
|
||||
convert_data_to_type(
|
||||
let head_list = if current_tipo.is_map() {
|
||||
apply_wrap(
|
||||
Term::Builtin(DefaultFunction::HeadList).force_wrap(),
|
||||
Term::Var(Name {
|
||||
text: format!("tail_index_{}_{}", current_index, id_list[current_index]),
|
||||
unique: 0.into(),
|
||||
}),
|
||||
),
|
||||
&tipo.clone().get_inner_types()[0],
|
||||
)
|
||||
};
|
||||
|
||||
if names.len() == 1 && tail {
|
||||
Term::Lambda {
|
||||
parameter_name: Name {
|
||||
text: format!("tail_index_{}_{}", current_index, id_list[current_index]),
|
||||
unique: 0.into(),
|
||||
},
|
||||
body: apply_wrap(
|
||||
Term::Lambda {
|
||||
parameter_name: Name {
|
||||
text: first.clone(),
|
||||
unique: 0.into(),
|
||||
},
|
||||
body: apply_wrap(
|
||||
Term::Lambda {
|
||||
parameter_name: Name {
|
||||
text: names[0].clone(),
|
||||
unique: 0.into(),
|
||||
},
|
||||
body: term.into(),
|
||||
},
|
||||
apply_wrap(
|
||||
Term::Builtin(DefaultFunction::TailList).force_wrap(),
|
||||
Term::Var(Name {
|
||||
text: format!(
|
||||
"tail_index_{}_{}",
|
||||
current_index, id_list[current_index]
|
||||
),
|
||||
unique: 0.into(),
|
||||
}),
|
||||
),
|
||||
)
|
||||
.into(),
|
||||
},
|
||||
head_list,
|
||||
)
|
||||
.into(),
|
||||
}
|
||||
} else if names.is_empty() {
|
||||
Term::Lambda {
|
||||
parameter_name: Name {
|
||||
text: format!("tail_index_{}_{}", current_index, id_list[current_index]),
|
||||
unique: 0.into(),
|
||||
},
|
||||
body: apply_wrap(
|
||||
Term::Lambda {
|
||||
parameter_name: Name {
|
||||
text: first.clone(),
|
||||
unique: 0.into(),
|
||||
},
|
||||
body: term.into(),
|
||||
},
|
||||
} else {
|
||||
convert_data_to_type(
|
||||
apply_wrap(
|
||||
Term::Builtin(DefaultFunction::HeadList).force_wrap(),
|
||||
Term::Var(Name {
|
||||
|
@ -565,40 +507,135 @@ pub fn list_access_to_uplc(
|
|||
unique: 0.into(),
|
||||
}),
|
||||
),
|
||||
¤t_tipo.to_owned(),
|
||||
)
|
||||
.into(),
|
||||
};
|
||||
|
||||
if names.len() == 1 && tail {
|
||||
Term::Lambda {
|
||||
parameter_name: Name {
|
||||
text: format!("tail_index_{}_{}", current_index, id_list[current_index]),
|
||||
unique: 0.into(),
|
||||
},
|
||||
body: apply_wrap(
|
||||
Term::Lambda {
|
||||
parameter_name: Name {
|
||||
text: first.clone(),
|
||||
unique: 0.into(),
|
||||
},
|
||||
body: apply_wrap(
|
||||
Term::Lambda {
|
||||
parameter_name: Name {
|
||||
text: names[0].clone(),
|
||||
unique: 0.into(),
|
||||
},
|
||||
body: term.into(),
|
||||
},
|
||||
apply_wrap(
|
||||
Term::Builtin(DefaultFunction::TailList).force_wrap(),
|
||||
Term::Var(Name {
|
||||
text: format!(
|
||||
"tail_index_{}_{}",
|
||||
current_index, id_list[current_index]
|
||||
),
|
||||
unique: 0.into(),
|
||||
}),
|
||||
),
|
||||
)
|
||||
.into(),
|
||||
},
|
||||
head_list,
|
||||
)
|
||||
.into(),
|
||||
}
|
||||
} else if names.is_empty() {
|
||||
Term::Lambda {
|
||||
parameter_name: Name {
|
||||
text: format!("tail_index_{}_{}", current_index, id_list[current_index]),
|
||||
unique: 0.into(),
|
||||
},
|
||||
body: apply_wrap(
|
||||
Term::Lambda {
|
||||
parameter_name: Name {
|
||||
text: first.clone(),
|
||||
unique: 0.into(),
|
||||
},
|
||||
body: if check_last_item {
|
||||
delayed_choose_list(
|
||||
apply_wrap(
|
||||
Term::Builtin(DefaultFunction::TailList).force_wrap(),
|
||||
Term::Var(Name {
|
||||
text: format!(
|
||||
"tail_index_{}_{}",
|
||||
current_index, id_list[current_index]
|
||||
),
|
||||
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(),
|
||||
}
|
||||
} else {
|
||||
Term::Lambda {
|
||||
parameter_name: Name {
|
||||
text: format!("tail_index_{}_{}", current_index, id_list[current_index]),
|
||||
unique: 0.into(),
|
||||
},
|
||||
body: apply_wrap(
|
||||
Term::Lambda {
|
||||
parameter_name: Name {
|
||||
text: first.clone(),
|
||||
unique: 0.into(),
|
||||
},
|
||||
body: apply_wrap(
|
||||
list_access_to_uplc(
|
||||
names,
|
||||
id_list,
|
||||
tail,
|
||||
current_index + 1,
|
||||
term,
|
||||
tipos.to_owned(),
|
||||
check_last_item,
|
||||
),
|
||||
apply_wrap(
|
||||
Term::Builtin(DefaultFunction::TailList).force_wrap(),
|
||||
Term::Var(Name {
|
||||
text: format!(
|
||||
"tail_index_{}_{}",
|
||||
current_index, id_list[current_index]
|
||||
),
|
||||
unique: 0.into(),
|
||||
}),
|
||||
),
|
||||
)
|
||||
.into(),
|
||||
},
|
||||
head_list,
|
||||
)
|
||||
.into(),
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Term::Lambda {
|
||||
parameter_name: Name {
|
||||
text: format!("tail_index_{}_{}", current_index, id_list[current_index]),
|
||||
unique: 0.into(),
|
||||
},
|
||||
body: apply_wrap(
|
||||
Term::Lambda {
|
||||
parameter_name: Name {
|
||||
text: first.clone(),
|
||||
unique: 0.into(),
|
||||
},
|
||||
body: apply_wrap(
|
||||
list_access_to_uplc(names, id_list, tail, current_index + 1, term, tipo),
|
||||
apply_wrap(
|
||||
Term::Builtin(DefaultFunction::TailList).force_wrap(),
|
||||
Term::Var(Name {
|
||||
text: format!(
|
||||
"tail_index_{}_{}",
|
||||
current_index, id_list[current_index]
|
||||
),
|
||||
unique: 0.into(),
|
||||
}),
|
||||
),
|
||||
)
|
||||
.into(),
|
||||
},
|
||||
head_list,
|
||||
)
|
||||
.into(),
|
||||
}
|
||||
term
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 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();
|
||||
|
@ -986,7 +1023,7 @@ pub fn wrap_validator_args(term: Term<Name>, arguments: Vec<TypedArg>) -> Term<N
|
|||
|
||||
pub fn monomorphize(
|
||||
ir: Vec<Air>,
|
||||
generic_types: HashMap<u64, Arc<Type>>,
|
||||
generic_types: IndexMap<u64, Arc<Type>>,
|
||||
full_type: &Arc<Type>,
|
||||
) -> (String, Vec<Air>) {
|
||||
let mut new_air = ir.clone();
|
||||
|
@ -1053,6 +1090,7 @@ pub fn monomorphize(
|
|||
tipo,
|
||||
names,
|
||||
tail,
|
||||
check_last_item,
|
||||
} => {
|
||||
if tipo.is_generic() {
|
||||
let mut tipo = tipo.clone();
|
||||
|
@ -1063,6 +1101,7 @@ pub fn monomorphize(
|
|||
names,
|
||||
tipo,
|
||||
tail,
|
||||
check_last_item,
|
||||
};
|
||||
needs_variant = true;
|
||||
}
|
||||
|
@ -1114,8 +1153,15 @@ pub fn monomorphize(
|
|||
needs_variant = true;
|
||||
}
|
||||
}
|
||||
// TODO check on assignment if type is needed
|
||||
Air::Assignment { .. } => {}
|
||||
Air::UnWrapData { scope, tipo } => {
|
||||
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 {
|
||||
scope,
|
||||
tipo,
|
||||
|
@ -1327,8 +1373,8 @@ pub fn monomorphize(
|
|||
}
|
||||
Air::FieldsExpose {
|
||||
scope,
|
||||
count,
|
||||
indices,
|
||||
check_last_item,
|
||||
} => {
|
||||
let mut new_indices = vec![];
|
||||
for (ind, name, tipo) in indices {
|
||||
|
@ -1343,16 +1389,18 @@ pub fn monomorphize(
|
|||
}
|
||||
new_air[index] = Air::FieldsExpose {
|
||||
scope,
|
||||
count,
|
||||
indices: new_indices,
|
||||
check_last_item,
|
||||
};
|
||||
}
|
||||
Air::RecordUpdate {
|
||||
scope,
|
||||
highest_index,
|
||||
indices,
|
||||
tipo,
|
||||
} => {
|
||||
let mut new_indices = vec![];
|
||||
let mut tipo = tipo.clone();
|
||||
for (ind, tipo) in indices {
|
||||
if tipo.is_generic() {
|
||||
let mut tipo = tipo.clone();
|
||||
|
@ -1363,18 +1411,51 @@ pub fn monomorphize(
|
|||
new_indices.push((ind, tipo));
|
||||
}
|
||||
}
|
||||
if tipo.is_generic() {
|
||||
find_generics_to_replace(&mut tipo, &generic_types);
|
||||
}
|
||||
new_air[index] = Air::RecordUpdate {
|
||||
scope,
|
||||
highest_index,
|
||||
indices: new_indices,
|
||||
tipo,
|
||||
};
|
||||
}
|
||||
Air::TupleAccessor { scope, names, tipo } => {
|
||||
Air::TupleAccessor {
|
||||
scope,
|
||||
names,
|
||||
tipo,
|
||||
check_last_item,
|
||||
} => {
|
||||
if tipo.is_generic() {
|
||||
let mut tipo = tipo.clone();
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -1393,14 +1474,14 @@ pub fn monomorphize(
|
|||
(new_name, new_air)
|
||||
}
|
||||
|
||||
pub fn handle_func_deps_ir(
|
||||
dep_ir: &mut Vec<Air>,
|
||||
pub fn handle_func_dependencies_ir(
|
||||
dependencies_ir: &mut Vec<Air>,
|
||||
funt_comp: &FuncComponents,
|
||||
func_components: &IndexMap<FunctionAccessKey, FuncComponents>,
|
||||
defined_functions: &mut HashMap<FunctionAccessKey, ()>,
|
||||
defined_functions: &mut IndexMap<FunctionAccessKey, ()>,
|
||||
func_index_map: &IndexMap<FunctionAccessKey, Vec<u64>>,
|
||||
func_scope: &[u64],
|
||||
to_be_defined: &mut HashMap<FunctionAccessKey, ()>,
|
||||
to_be_defined: &mut IndexMap<FunctionAccessKey, ()>,
|
||||
) {
|
||||
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(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() {
|
||||
defined_functions.insert(dependency, ());
|
||||
}
|
||||
|
@ -1492,10 +1573,11 @@ pub fn handle_recursion_ir(
|
|||
let current_call = recursion_ir[index - 1].clone();
|
||||
|
||||
match current_call {
|
||||
Air::Call { scope, count } => {
|
||||
Air::Call { scope, count, tipo } => {
|
||||
recursion_ir[index - 1] = Air::Call {
|
||||
scope,
|
||||
count: count + 1,
|
||||
tipo,
|
||||
}
|
||||
}
|
||||
_ => unreachable!(),
|
||||
|
@ -1504,7 +1586,7 @@ pub fn handle_recursion_ir(
|
|||
}
|
||||
|
||||
pub fn lookup_data_type_by_tipo(
|
||||
data_types: HashMap<DataTypeKey, &TypedDataType>,
|
||||
data_types: IndexMap<DataTypeKey, &TypedDataType>,
|
||||
tipo: &Type,
|
||||
) -> Option<DataType<Arc<Type>>> {
|
||||
match tipo {
|
||||
|
@ -1539,7 +1621,7 @@ pub fn lookup_data_type_by_tipo(
|
|||
|
||||
pub fn check_replaceable_opaque_type(
|
||||
t: &Arc<Type>,
|
||||
data_types: &HashMap<DataTypeKey, &TypedDataType>,
|
||||
data_types: &IndexMap<DataTypeKey, &TypedDataType>,
|
||||
) -> bool {
|
||||
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 { .. }) {
|
||||
let data_type = lookup_data_type_by_tipo(data_types.clone(), t).unwrap();
|
||||
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()) {
|
||||
let mut map = generics_type_map.into_iter().collect_vec();
|
||||
|
|
|
@ -52,8 +52,8 @@ pub fn lexer() -> impl Parser<char, Vec<(Token, Span)>, Error = ParseError> {
|
|||
just('|').to(Token::Vbar),
|
||||
just("&&").to(Token::AmperAmper),
|
||||
just('#').to(Token::Hash),
|
||||
just("\n\n").to(Token::EmptyLine),
|
||||
just("\n").to(Token::NewLine),
|
||||
choice((just("\n\n"), just("\r\n\r\n"))).to(Token::EmptyLine),
|
||||
choice((just("\n"), just("\r\n"))).to(Token::NewLine),
|
||||
));
|
||||
|
||||
let grouping = choice((
|
||||
|
|
|
@ -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]
|
||||
fn import() {
|
||||
let code = indoc! {r#"
|
||||
|
|
|
@ -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 {
|
||||
match self {
|
||||
Type::App { args, .. } => {
|
||||
|
@ -205,6 +213,7 @@ impl Type {
|
|||
match self {
|
||||
Self::Fn { args, .. } => Some(args.clone()),
|
||||
Self::App { args, .. } => Some(args.clone()),
|
||||
Self::Var { tipo } => tipo.borrow().arg_types(),
|
||||
_ => 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 {
|
||||
match self {
|
||||
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>> {
|
||||
match self {
|
||||
Self::Link { tipo } => tipo.get_inner_types(),
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use super::Type;
|
||||
use crate::{
|
||||
ast::{Annotation, BinOp, CallArg, Span, TodoKind, UntypedPattern},
|
||||
expr,
|
||||
expr::{self, UntypedExpr},
|
||||
format::Formatter,
|
||||
levenshtein,
|
||||
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:
|
||||
|
||||
{sample}"#
|
||||
, sample = Formatter::new()
|
||||
.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("")
|
||||
, sample = format_suggestion(expr)
|
||||
))]
|
||||
LastExpressionIsAssignment {
|
||||
#[label("let-binding as last expression")]
|
||||
|
@ -737,6 +724,15 @@ The best thing to do from here is to remove it."#))]
|
|||
location: Span,
|
||||
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 {
|
||||
|
@ -1034,14 +1030,12 @@ fn suggest_import_constructor() -> String {
|
|||
|
||||
#[derive(Debug, PartialEq, Clone, thiserror::Error, Diagnostic)]
|
||||
pub enum Warning {
|
||||
#[error("I found a todo left in the code.\n")]
|
||||
#[diagnostic(help("You probably want to replace that one with real code... eventually."))]
|
||||
#[diagnostic(code("todo"))]
|
||||
Todo {
|
||||
kind: TodoKind,
|
||||
#[error("I found a record update using all fields; thus redundant.\n")]
|
||||
#[diagnostic(url("https://aiken-lang.org/language-tour/custom-types#record-updates"))]
|
||||
#[diagnostic(code("record_update::all_fields"))]
|
||||
AllFieldsRecordUpdate {
|
||||
#[label]
|
||||
location: Span,
|
||||
tipo: Arc<Type>,
|
||||
},
|
||||
|
||||
#[error(
|
||||
|
@ -1056,9 +1050,10 @@ pub enum Warning {
|
|||
location: Span,
|
||||
},
|
||||
|
||||
#[error("I found a literal that is unused.\n")]
|
||||
#[diagnostic(code("unused::literal"))]
|
||||
UnusedLiteral {
|
||||
#[error("I found a record update with no fields; effectively updating nothing.\n")]
|
||||
#[diagnostic(url("https://aiken-lang.org/language-tour/custom-types#record-updates"))]
|
||||
#[diagnostic(code("record_update::no_fields"))]
|
||||
NoFieldsRecordUpdate {
|
||||
#[label]
|
||||
location: Span,
|
||||
},
|
||||
|
@ -1070,29 +1065,25 @@ pub enum Warning {
|
|||
location: Span,
|
||||
},
|
||||
|
||||
#[error("I found a record update with no fields; effectively updating nothing.\n")]
|
||||
#[diagnostic(url("https://aiken-lang.org/language-tour/custom-types#record-updates"))]
|
||||
#[diagnostic(code("record_update::no_fields"))]
|
||||
NoFieldsRecordUpdate {
|
||||
#[label]
|
||||
#[error("I found a when expression with a single clause.")]
|
||||
#[diagnostic(
|
||||
code("single_when_clause"),
|
||||
help("Prefer using a {} binding like so...\n\n{}", "let".purple(), format_suggestion(sample))
|
||||
)]
|
||||
SingleWhenClause {
|
||||
#[label("use let")]
|
||||
location: Span,
|
||||
sample: UntypedExpr,
|
||||
},
|
||||
|
||||
#[error("I found a record update using all fields; thus redundant.\n")]
|
||||
#[diagnostic(url("https://aiken-lang.org/language-tour/custom-types#record-updates"))]
|
||||
#[diagnostic(code("record_update::all_fields"))]
|
||||
AllFieldsRecordUpdate {
|
||||
#[error("I found a todo left in the code.\n")]
|
||||
#[diagnostic(help("You probably want to replace that one with real code... eventually."))]
|
||||
#[diagnostic(code("todo"))]
|
||||
Todo {
|
||||
kind: TodoKind,
|
||||
#[label]
|
||||
location: Span,
|
||||
},
|
||||
|
||||
#[error("I discovered an unused type: '{}'.\n", name.purple())]
|
||||
#[diagnostic(code("unused::type"))]
|
||||
UnusedType {
|
||||
#[label]
|
||||
location: Span,
|
||||
imported: bool,
|
||||
name: String,
|
||||
tipo: Arc<Type>,
|
||||
},
|
||||
|
||||
#[error("I discovered an unused constructor: '{}'.\n", name.purple())]
|
||||
|
@ -1107,6 +1098,17 @@ pub enum Warning {
|
|||
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())]
|
||||
#[diagnostic(help(
|
||||
"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,
|
||||
},
|
||||
|
||||
#[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(
|
||||
"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"))]
|
||||
UnusedImportedModule {
|
||||
#[diagnostic(code("unused::function"))]
|
||||
UnusedPrivateFunction {
|
||||
#[label]
|
||||
location: Span,
|
||||
name: String,
|
||||
|
@ -1142,16 +1153,12 @@ pub enum Warning {
|
|||
name: String,
|
||||
},
|
||||
|
||||
#[error("I found an unused private function: '{}'.\n", name.purple())]
|
||||
#[diagnostic(help(
|
||||
"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::function"))]
|
||||
UnusedPrivateFunction {
|
||||
#[error("I discovered an unused type: '{}'.\n", name.purple())]
|
||||
#[diagnostic(code("unused::type"))]
|
||||
UnusedType {
|
||||
#[label]
|
||||
location: Span,
|
||||
imported: bool,
|
||||
name: String,
|
||||
},
|
||||
|
||||
|
@ -1187,3 +1194,20 @@ pub enum UnknownRecordFieldSituation {
|
|||
/// This unknown record field is being called as a function. i.e. `record.field()`
|
||||
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("")
|
||||
}
|
||||
|
|
|
@ -807,8 +807,8 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
|||
annotation: &Option<Annotation>,
|
||||
location: Span,
|
||||
) -> Result<TypedExpr, Error> {
|
||||
let value = self.in_new_scope(|value_typer| value_typer.infer(value))?;
|
||||
let mut value_typ = value.tipo();
|
||||
let typed_value = self.in_new_scope(|value_typer| value_typer.infer(value.clone()))?;
|
||||
let mut value_typ = typed_value.tipo();
|
||||
|
||||
// Check that any type annotation is accurate.
|
||||
let pattern = if let Some(ann) = annotation {
|
||||
|
@ -819,7 +819,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
|||
self.unify(
|
||||
ann_typ.clone(),
|
||||
value_typ.clone(),
|
||||
value.type_defining_location(),
|
||||
typed_value.type_defining_location(),
|
||||
)?;
|
||||
|
||||
value_typ = ann_typ.clone();
|
||||
|
@ -831,6 +831,24 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
|||
Some(ann_typ),
|
||||
)?
|
||||
} 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
|
||||
PatternTyper::new(self.environment, &self.hydrator).unify(
|
||||
pattern,
|
||||
|
@ -860,7 +878,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
|||
tipo: value_typ,
|
||||
kind,
|
||||
pattern,
|
||||
value: Box::new(value),
|
||||
value: Box::new(typed_value),
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -1906,6 +1924,21 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
|||
clauses: Vec<UntypedClause>,
|
||||
location: Span,
|
||||
) -> 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 mut typed_subjects = Vec::with_capacity(subjects_count);
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -16,6 +16,7 @@ fslock = "0.2.1"
|
|||
futures = "0.3.25"
|
||||
hex = "0.4.3"
|
||||
ignore = "0.4.18"
|
||||
indexmap = "1.9.1"
|
||||
itertools = "0.10.1"
|
||||
miette = { version = "5.3.0", features = ["fancy"] }
|
||||
owo-colors = "3.5.0"
|
||||
|
|
|
@ -20,6 +20,7 @@ use aiken_lang::{
|
|||
IdGenerator, MINT, PUBLISH, SPEND, VALIDATOR_NAMES, WITHDRAW,
|
||||
};
|
||||
use deps::UseManifest;
|
||||
use indexmap::IndexMap;
|
||||
use miette::NamedSource;
|
||||
use options::{CodeGenMode, Options};
|
||||
use package_name::PackageName;
|
||||
|
@ -482,9 +483,9 @@ where
|
|||
validators: Vec<(PathBuf, String, TypedFunction)>,
|
||||
) -> Result<Vec<Script>, Error> {
|
||||
let mut programs = Vec::new();
|
||||
let mut functions = HashMap::new();
|
||||
let mut type_aliases = HashMap::new();
|
||||
let mut data_types = HashMap::new();
|
||||
let mut functions = IndexMap::new();
|
||||
let mut type_aliases = IndexMap::new();
|
||||
let mut data_types = IndexMap::new();
|
||||
|
||||
let prelude_functions = builtins::prelude_functions(&self.id_gen);
|
||||
for (access_key, func) in prelude_functions.iter() {
|
||||
|
@ -539,11 +540,15 @@ where
|
|||
..
|
||||
} = func_def;
|
||||
|
||||
let mut modules_map = IndexMap::new();
|
||||
|
||||
modules_map.extend(self.module_types.clone());
|
||||
|
||||
let mut generator = CodeGenerator::new(
|
||||
&functions,
|
||||
// &type_aliases,
|
||||
&data_types,
|
||||
&self.module_types,
|
||||
&modules_map,
|
||||
);
|
||||
|
||||
self.event_listener.handle_event(Event::GeneratingUPLC {
|
||||
|
@ -573,9 +578,9 @@ where
|
|||
should_collect: fn(&TypedDefinition) -> bool,
|
||||
) -> Result<Vec<Script>, Error> {
|
||||
let mut programs = Vec::new();
|
||||
let mut functions = HashMap::new();
|
||||
let mut type_aliases = HashMap::new();
|
||||
let mut data_types = HashMap::new();
|
||||
let mut functions = IndexMap::new();
|
||||
let mut type_aliases = IndexMap::new();
|
||||
let mut data_types = IndexMap::new();
|
||||
|
||||
let prelude_functions = builtins::prelude_functions(&self.id_gen);
|
||||
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(
|
||||
&functions,
|
||||
// &type_aliases,
|
||||
&data_types,
|
||||
&self.module_types,
|
||||
&modules_map,
|
||||
);
|
||||
|
||||
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)
|
||||
.try_into()
|
||||
.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)
|
||||
.try_into()
|
||||
.unwrap();
|
||||
|
|
|
@ -5,6 +5,7 @@ use super::{Constant, Name, Term};
|
|||
pub const CONSTR_FIELDS_EXPOSER: &str = "__constr_fields_exposer";
|
||||
pub const CONSTR_INDEX_EXPOSER: &str = "__constr_index_exposer";
|
||||
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> {
|
||||
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> {
|
||||
Term::Apply {
|
||||
function: Term::Lambda {
|
||||
|
|
|
@ -343,7 +343,7 @@ impl Machine {
|
|||
Err(Error::UnexpectedBuiltinTermArgument(t.as_ref().clone()))
|
||||
}
|
||||
}
|
||||
rest => Err(Error::NonFunctionalApplication(rest)),
|
||||
rest => Err(Error::NonFunctionalApplication(rest, argument)),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -16,8 +16,8 @@ pub enum Error {
|
|||
EvaluationFailure,
|
||||
#[error("Attempted to instantiate a non-polymorphic term:\n\n{0:#?}")]
|
||||
NonPolymorphicInstantiation(Value),
|
||||
#[error("Attempted to apply a non-function:\n\n{0:#?}")]
|
||||
NonFunctionalApplication(Value),
|
||||
#[error("Attempted to apply a non-function:\n\n{0:#?} to argument:\n\n{1:#?}")]
|
||||
NonFunctionalApplication(Value, Value),
|
||||
#[error("Type mismatch expected '{0}' got '{1}'")]
|
||||
TypeMismatch(Type, Type),
|
||||
#[error("Type mismatch expected '(list a)' got '{0}'")]
|
||||
|
|
|
@ -1 +1 @@
|
|||
addr1w9zyujfu4a23cltkm7xe2usj7wedtvqnsk9ecg2zwt6a90s83wahe
|
||||
addr1w8ehrka3eyh8hqxt647qm56z0ju3x8fsyjv2f3cwp5kr5ssvegjnw
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"type": "PlutusScriptV2",
|
||||
"description": "Generated by Aiken",
|
||||
"cborHex": "59015159014e01000022253335734646464646466002006464646464646464646600201291010500000000000022323232300c00130050013300500100237566601c601e00490011192999aab9f00114a2294000488c8c8cc0140052f5bded8c06600a002004004446464a666ae68cdc3800a40042006264640026eacd5d080098070011aab9d37540020044466006004002600200244464a666aae7c0044cdd2a400497ae01323232325333573466e3c0180044cdd2a400066ae80dd300125eb804ccc02002000c018dd71aab9d00337566aae78008d5d10011aba100100223335734002941289800800911192999aab9f00114a026464a666ae68c01000852889998030030008021aba2002357420020046eb0cc004c008cc004c00800d20004801088c8ccc00400520000032223333573466e1c0100095d0919980200219b8000348008d5d100080091aab9e37540022930b1"
|
||||
"cborHex": "59015159014e01000022253335734646464646466002006464646464646464646600201291010500000000000022323232300600130060013300600100237566601c601e00490011199ab9a0014a09448c94ccd55cf8008a5114a00024464646600a00297adef6c60330050010020022232325333573466e1c005200210031323200137566ae84004c034008d55ce9baa001002223300300200130010012223253335573e002266e9520024bd700991919192999ab9a3371e00c002266e9520003357406e980092f5c0266601001000600c6eb8d55ce8019bab35573c0046ae88008d5d08008011800800911192999aab9f00114a026464a666ae68c01000852889998030030008021aba2002357420020046eb0cc004c008cc004c00800d20004801088c8ccc00400520000032223333573466e1c0100095d0919980200219b8000348008d5d100080091aab9e37540022930b1"
|
||||
}
|
|
@ -1 +1 @@
|
|||
59014e01000022253335734646464646466002006464646464646464646600201291010500000000000022323232300c00130050013300500100237566601c601e00490011192999aab9f00114a2294000488c8c8cc0140052f5bded8c06600a002004004446464a666ae68cdc3800a40042006264640026eacd5d080098070011aab9d37540020044466006004002600200244464a666aae7c0044cdd2a400497ae01323232325333573466e3c0180044cdd2a400066ae80dd300125eb804ccc02002000c018dd71aab9d00337566aae78008d5d10011aba100100223335734002941289800800911192999aab9f00114a026464a666ae68c01000852889998030030008021aba2002357420020046eb0cc004c008cc004c00800d20004801088c8ccc00400520000032223333573466e1c0100095d0919980200219b8000348008d5d100080091aab9e37540022930b1
|
||||
59014e01000022253335734646464646466002006464646464646464646600201291010500000000000022323232300600130060013300600100237566601c601e00490011199ab9a0014a09448c94ccd55cf8008a5114a00024464646600a00297adef6c60330050010020022232325333573466e1c005200210031323200137566ae84004c034008d55ce9baa001002223300300200130010012223253335573e002266e9520024bd700991919192999ab9a3371e00c002266e9520003357406e980092f5c0266601001000600c6eb8d55ce8019bab35573c0046ae88008d5d08008011800800911192999aab9f00114a026464a666ae68c01000852889998030030008021aba2002357420020046eb0cc004c008cc004c00800d20004801088c8ccc00400520000032223333573466e1c0100095d0919980200219b8000348008d5d100080091aab9e37540022930b1
|
|
@ -1 +1 @@
|
|||
addr_test1wpzyujfu4a23cltkm7xe2usj7wedtvqnsk9ecg2zwt6a90sue6pcu
|
||||
addr_test1wrehrka3eyh8hqxt647qm56z0ju3x8fsyjv2f3cwp5kr5ssh3uwut
|
|
@ -1,3 +1,9 @@
|
|||
pub type Door{
|
||||
angle: Int,
|
||||
locked: Bool
|
||||
}
|
||||
|
||||
|
||||
pub type Car {
|
||||
Honda { remote_connect: ByteArray, owner: ByteArray, wheels: Int }
|
||||
Ford {
|
||||
|
@ -5,18 +11,19 @@ pub type Car {
|
|||
owner: ByteArray,
|
||||
wheels: Int,
|
||||
truck_bed_limit: Int,
|
||||
car_doors: List<Door>
|
||||
}
|
||||
}
|
||||
|
||||
// test update_owner2_should_fail(){
|
||||
// let initial_car: Data = Ford{remote_connect: #[], owner: #[], wheels: 4, truck_bed_limit: 10000}
|
||||
// assert Honda{ owner, ..} = initial_car
|
||||
// let initial_car: Data = Ford{remote_connect: #[], owner: #[], wheels: 4, truck_bed_limit: 10000, car_doors: []}
|
||||
// assert Honda{ owner, ..}: Car = initial_car
|
||||
// owner == #[]
|
||||
// }
|
||||
|
||||
test update_owner1() {
|
||||
let initial_car: Data =
|
||||
Ford { remote_connect: #[], owner: #[], wheels: 4, truck_bed_limit: 10000 }
|
||||
assert Ford { owner, .. } = initial_car
|
||||
Ford { remote_connect: #[], owner: #[], wheels: 4, truck_bed_limit: 10000, car_doors: [] }
|
||||
assert Ford { owner, .. }: Car = initial_car
|
||||
owner == #[]
|
||||
}
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
# This file was generated by Aiken
|
||||
# You typically do not need to edit this file
|
||||
|
||||
requirements = []
|
||||
packages = []
|
|
@ -0,0 +1,3 @@
|
|||
name = 'aiken-lang/acceptance_test_046'
|
||||
version = '0.0.0'
|
||||
description = ''
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
Loading…
Reference in New Issue