Merge pull request #238 from aiken-lang/record-update

Nested list fix and Boolean constant fix
This commit is contained in:
Matthias Benkort 2023-01-06 14:30:59 +01:00 committed by GitHub
commit a51736187f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 166 additions and 139 deletions

View File

@ -11,18 +11,16 @@ env:
jobs: jobs:
build: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- name: Build - name: Build
run: cargo build --verbose --workspace run: cargo build --verbose --workspace
- name: Run tests - name: Run unit tests
run: cargo test --verbose --workspace run: cargo test --verbose --workspace
- name: Acceptance Tests - name: Run acceptance tests
working-directory: examples/acceptance_tests working-directory: examples/acceptance_tests
run: ./run-all run: find . -maxdepth 1 -mindepth 1 -type d -exec ./run {} \;
- name: Lint - name: Lint
run: cargo fmt --all -- --check run: cargo fmt --all -- --check
- name: Clippy - name: Clippy

View File

@ -3,7 +3,7 @@ use std::{collections::HashSet, sync::Arc};
use uplc::builtins::DefaultFunction; use uplc::builtins::DefaultFunction;
use crate::{ use crate::{
ast::{AssignmentKind, BinOp, TypedRecordUpdateArg, UnOp}, ast::{AssignmentKind, BinOp, UnOp},
tipo::{Type, ValueConstructor}, tipo::{Type, ValueConstructor},
}; };
@ -134,7 +134,6 @@ pub enum Air {
tail_name: String, tail_name: String,
next_tail_name: Option<String>, next_tail_name: Option<String>,
complex_clause: bool, complex_clause: bool,
inverse: bool,
}, },
TupleClause { TupleClause {
@ -153,6 +152,14 @@ pub enum Air {
tipo: Arc<Type>, tipo: Arc<Type>,
}, },
ListClauseGuard {
scope: Vec<u64>,
tipo: Arc<Type>,
tail_name: String,
next_tail_name: Option<String>,
inverse: bool,
},
Discard { Discard {
scope: Vec<u64>, scope: Vec<u64>,
}, },
@ -224,8 +231,7 @@ pub enum Air {
RecordUpdate { RecordUpdate {
scope: Vec<u64>, scope: Vec<u64>,
tipo: Arc<Type>, tipo: Arc<Type>,
spread: Box<Self>, count: usize,
args: Vec<TypedRecordUpdateArg>,
}, },
UnOp { UnOp {
@ -264,6 +270,7 @@ impl Air {
| Air::Clause { scope, .. } | Air::Clause { scope, .. }
| Air::ListClause { scope, .. } | Air::ListClause { scope, .. }
| Air::ClauseGuard { scope, .. } | Air::ClauseGuard { scope, .. }
| Air::ListClauseGuard { scope, .. }
| Air::Discard { scope } | Air::Discard { scope }
| Air::Finally { scope } | Air::Finally { scope }
| Air::If { scope, .. } | Air::If { scope, .. }

View File

@ -1038,7 +1038,7 @@ pub fn convert_constants_to_data(constants: Vec<UplcConstant>) -> Vec<UplcConsta
)), )),
UplcConstant::Bool(b) => UplcConstant::Data(PlutusData::Constr(Constr { UplcConstant::Bool(b) => UplcConstant::Data(PlutusData::Constr(Constr {
tag: u64::from(b), tag: convert_constr_to_tag(b.into()),
any_constructor: None, any_constructor: None,
fields: vec![], fields: vec![],
})), })),
@ -1170,7 +1170,7 @@ pub fn monomorphize(
tipo, tipo,
tail, tail,
}; };
needs_variant = false; needs_variant = true;
} }
} }
Air::ListAccessor { Air::ListAccessor {
@ -1189,7 +1189,7 @@ pub fn monomorphize(
tipo, tipo,
tail, tail,
}; };
needs_variant = false; needs_variant = true;
} }
} }
Air::ListExpose { Air::ListExpose {
@ -1208,7 +1208,7 @@ pub fn monomorphize(
tipo, tipo,
tail, tail,
}; };
needs_variant = false; needs_variant = true;
} }
} }
Air::BinOp { Air::BinOp {
@ -1227,7 +1227,7 @@ pub fn monomorphize(
tipo, tipo,
count, count,
}; };
needs_variant = false; needs_variant = true;
} }
} }
Air::Builtin { scope, func, tipo } => { Air::Builtin { scope, func, tipo } => {
@ -1236,7 +1236,7 @@ pub fn monomorphize(
find_generics_to_replace(&mut tipo, &generic_types); find_generics_to_replace(&mut tipo, &generic_types);
new_air[index] = Air::Builtin { scope, func, tipo }; new_air[index] = Air::Builtin { scope, func, tipo };
needs_variant = false; needs_variant = true;
} }
} }
// TODO check on assignment if type is needed // TODO check on assignment if type is needed
@ -1255,7 +1255,7 @@ pub fn monomorphize(
subject_name, subject_name,
tipo, tipo,
}; };
needs_variant = false; needs_variant = true;
} }
} }
Air::Clause { Air::Clause {
@ -1274,7 +1274,7 @@ pub fn monomorphize(
subject_name, subject_name,
complex_clause, complex_clause,
}; };
needs_variant = false; needs_variant = true;
} }
} }
Air::ListClause { Air::ListClause {
@ -1283,7 +1283,6 @@ pub fn monomorphize(
tail_name, tail_name,
complex_clause, complex_clause,
next_tail_name, next_tail_name,
inverse,
} => { } => {
if tipo.is_generic() { if tipo.is_generic() {
let mut tipo = tipo.clone(); let mut tipo = tipo.clone();
@ -1295,9 +1294,8 @@ pub fn monomorphize(
tail_name, tail_name,
complex_clause, complex_clause,
next_tail_name, next_tail_name,
inverse,
}; };
needs_variant = false; needs_variant = true;
} }
} }
Air::ClauseGuard { Air::ClauseGuard {
@ -1314,7 +1312,28 @@ pub fn monomorphize(
subject_name, subject_name,
tipo, tipo,
}; };
needs_variant = false; needs_variant = true;
}
}
Air::ListClauseGuard {
scope,
tipo,
tail_name,
next_tail_name,
inverse,
} => {
if tipo.is_generic() {
let mut tipo = tipo.clone();
find_generics_to_replace(&mut tipo, &generic_types);
new_air[index] = Air::ListClauseGuard {
scope,
tipo,
tail_name,
next_tail_name,
inverse,
};
needs_variant = true;
} }
} }
Air::RecordAccess { Air::RecordAccess {
@ -1331,7 +1350,7 @@ pub fn monomorphize(
index: record_index, index: record_index,
tipo, tipo,
}; };
needs_variant = false; needs_variant = true;
} }
} }
Air::FieldsExpose { Air::FieldsExpose {
@ -1344,7 +1363,7 @@ pub fn monomorphize(
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);
needs_variant = false; needs_variant = true;
new_indices.push((ind, name, tipo)); new_indices.push((ind, name, tipo));
} else { } else {
new_indices.push((ind, name, tipo)); new_indices.push((ind, name, tipo));
@ -1362,7 +1381,7 @@ pub fn monomorphize(
find_generics_to_replace(&mut tipo, &generic_types); find_generics_to_replace(&mut tipo, &generic_types);
new_air[index] = Air::Tuple { scope, count, tipo }; new_air[index] = Air::Tuple { scope, count, tipo };
needs_variant = false; needs_variant = true;
} }
} }
Air::Todo { scope, label, tipo } => { Air::Todo { scope, label, tipo } => {
@ -1371,17 +1390,25 @@ pub fn monomorphize(
find_generics_to_replace(&mut tipo, &generic_types); find_generics_to_replace(&mut tipo, &generic_types);
new_air[index] = Air::Todo { scope, label, tipo }; new_air[index] = Air::Todo { scope, label, tipo };
needs_variant = false; needs_variant = true;
}
}
Air::RecordUpdate { scope, tipo, count } => {
if tipo.is_generic() {
let mut tipo = tipo.clone();
find_generics_to_replace(&mut tipo, &generic_types);
new_air[index] = Air::RecordUpdate { scope, tipo, count };
needs_variant = true;
} }
} }
Air::RecordUpdate { .. } => todo!(),
Air::TupleAccessor { scope, names, tipo } => { Air::TupleAccessor { scope, names, tipo } => {
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 };
needs_variant = false; needs_variant = true;
} }
} }
Air::TupleClause { Air::TupleClause {
@ -1406,7 +1433,7 @@ pub fn monomorphize(
count, count,
complex_clause, complex_clause,
}; };
needs_variant = false; needs_variant = true;
} }
} }
_ => {} _ => {}

View File

@ -477,7 +477,28 @@ impl<'a> CodeGenerator<'a> {
tipo: tipo.clone(), tipo: tipo.clone(),
}); });
} }
TypedExpr::RecordUpdate { .. } => todo!(), TypedExpr::RecordUpdate {
tipo, spread, args, ..
} => {
let mut update_ir = vec![];
let mut spread_scope = scope.clone();
spread_scope.push(self.id_gen.next());
self.build_ir(spread, &mut update_ir, spread_scope);
for arg in args {
let mut arg_scope = scope.clone();
arg_scope.push(self.id_gen.next());
self.build_ir(&arg.value, &mut update_ir, arg_scope)
}
ir_stack.push(Air::RecordUpdate {
scope,
tipo: tipo.clone(),
count: args.len(),
});
}
TypedExpr::UnOp { value, op, .. } => { TypedExpr::UnOp { value, op, .. } => {
ir_stack.push(Air::UnOp { ir_stack.push(Air::UnOp {
scope: scope.clone(), scope: scope.clone(),
@ -617,7 +638,6 @@ impl<'a> CodeGenerator<'a> {
tail_name: subject_name, tail_name: subject_name,
next_tail_name: next_tail, next_tail_name: next_tail,
complex_clause: *clause_properties.is_complex_clause(), complex_clause: *clause_properties.is_complex_clause(),
inverse: false,
}); });
match clause_properties { match clause_properties {
@ -955,7 +975,7 @@ impl<'a> CodeGenerator<'a> {
tail_head_names, tail_head_names,
tail: Some((tail_var, tail_name)), tail: Some((tail_var, tail_name)),
}); });
} else { } else if !elements.is_empty() {
pattern_vec.push(Air::ListExpose { pattern_vec.push(Air::ListExpose {
scope, scope,
tipo: tipo.clone().into(), tipo: tipo.clone().into(),
@ -1191,30 +1211,15 @@ impl<'a> CodeGenerator<'a> {
let new_tail_name = "__list_tail".to_string(); let new_tail_name = "__list_tail".to_string();
if elements.is_empty() { if elements.is_empty() {
pattern_vec.push(Air::ListClause { pattern_vec.push(Air::ListClauseGuard {
scope: scope.clone(), scope: scope.clone(),
tipo: pattern_type.clone(), tipo: pattern_type.clone(),
tail_name: item_name.clone(), tail_name: item_name.clone(),
next_tail_name: None, next_tail_name: None,
complex_clause: false, inverse: false,
inverse: true,
}); });
pattern_vec.push(Air::Discard { pattern_vec.push(Air::Discard { scope });
scope: scope.clone(),
});
pattern_vec.push(Air::Var {
scope,
constructor: ValueConstructor::public(
pattern_type.clone(),
ValueConstructorVariant::LocalVariable {
location: Span::empty(),
},
),
name: "__other_clauses_delayed".to_string(),
variant_name: String::new(),
});
} else { } else {
for (index, _) in elements.iter().enumerate() { for (index, _) in elements.iter().enumerate() {
let prev_tail_name = if index == 0 { let prev_tail_name = if index == 0 {
@ -1241,29 +1246,12 @@ impl<'a> CodeGenerator<'a> {
_ => unreachable!(), _ => unreachable!(),
}; };
pattern_vec.push(Air::ListClause { pattern_vec.push(Air::ListClauseGuard {
scope: scope.clone(), scope: scope.clone(),
tipo: pattern_type.clone(), tipo: pattern_type.clone(),
tail_name: prev_tail_name, tail_name: prev_tail_name,
next_tail_name: Some(tail_name), next_tail_name: Some(tail_name),
complex_clause: false, inverse: true,
inverse: false,
});
pattern_vec.push(Air::Discard {
scope: scope.clone(),
});
pattern_vec.push(Air::Var {
scope: scope.clone(),
constructor: ValueConstructor::public(
pattern_type.clone(),
ValueConstructorVariant::LocalVariable {
location: Span::empty(),
},
),
name: "__other_clauses_delayed".to_string(),
variant_name: "".to_string(),
}); });
self.when_ir( self.when_ir(
@ -1275,37 +1263,11 @@ impl<'a> CodeGenerator<'a> {
scope.clone(), scope.clone(),
); );
} else { } else {
pattern_vec.push(Air::ListClause { pattern_vec.push(Air::ListClauseGuard {
scope: scope.clone(), scope: scope.clone(),
tipo: pattern_type.clone(), tipo: pattern_type.clone(),
tail_name: prev_tail_name, tail_name: prev_tail_name,
next_tail_name: Some(tail_name.clone()), next_tail_name: Some(tail_name.clone()),
complex_clause: false,
inverse: false,
});
pattern_vec.push(Air::Discard {
scope: scope.clone(),
});
pattern_vec.push(Air::Var {
scope: scope.clone(),
constructor: ValueConstructor::public(
pattern_type.clone(),
ValueConstructorVariant::LocalVariable {
location: Span::empty(),
},
),
name: "__other_clauses_delayed".to_string(),
variant_name: String::new(),
});
pattern_vec.push(Air::ListClause {
scope: scope.clone(),
tipo: pattern_type.clone(),
tail_name: tail_name.clone(),
next_tail_name: None,
complex_clause: false,
inverse: true, inverse: true,
}); });
@ -1313,16 +1275,12 @@ impl<'a> CodeGenerator<'a> {
scope: scope.clone(), scope: scope.clone(),
}); });
pattern_vec.push(Air::Var { pattern_vec.push(Air::ListClauseGuard {
scope: scope.clone(), scope: scope.clone(),
constructor: ValueConstructor::public( tipo: pattern_type.clone(),
pattern_type.clone(), tail_name: tail_name.clone(),
ValueConstructorVariant::LocalVariable { next_tail_name: None,
location: Span::empty(), inverse: false,
},
),
name: "__other_clauses_delayed".to_string(),
variant_name: String::new(),
}); });
self.when_ir( self.when_ir(
@ -1341,29 +1299,12 @@ impl<'a> CodeGenerator<'a> {
_ => unreachable!(), _ => unreachable!(),
}; };
pattern_vec.push(Air::ListClause { pattern_vec.push(Air::ListClauseGuard {
scope: scope.clone(), scope: scope.clone(),
tipo: pattern_type.clone(), tipo: pattern_type.clone(),
tail_name: prev_tail_name, tail_name: prev_tail_name,
next_tail_name: Some(tail_name), next_tail_name: Some(tail_name),
complex_clause: false, inverse: true,
inverse: false,
});
pattern_vec.push(Air::Discard {
scope: scope.clone(),
});
pattern_vec.push(Air::Var {
scope: scope.clone(),
constructor: ValueConstructor::public(
pattern_type.clone(),
ValueConstructorVariant::LocalVariable {
location: Span::empty(),
},
),
name: "__other_clauses_delayed".to_string(),
variant_name: "".to_string(),
}); });
self.when_ir( self.when_ir(
@ -3482,7 +3423,6 @@ impl<'a> CodeGenerator<'a> {
.into(), .into(),
argument: Term::Delay(term.into()).into(), argument: Term::Delay(term.into()).into(),
} }
.force_wrap()
} else { } else {
term = delayed_if_else( term = delayed_if_else(
Term::Apply { Term::Apply {
@ -3499,26 +3439,14 @@ impl<'a> CodeGenerator<'a> {
Air::ListClause { Air::ListClause {
tail_name, tail_name,
next_tail_name, next_tail_name,
inverse,
complex_clause, complex_clause,
.. ..
} => { } => {
// discard to pop off // discard to pop off
let _ = arg_stack.pop().unwrap(); let _ = arg_stack.pop().unwrap();
// the body to be run if the clause matches
// the next branch in the when expression
let (body, mut term) = if inverse {
let term = arg_stack.pop().unwrap();
let body = arg_stack.pop().unwrap(); let body = arg_stack.pop().unwrap();
let mut term = arg_stack.pop().unwrap();
(body, term)
} else {
let body = arg_stack.pop().unwrap();
let term = arg_stack.pop().unwrap();
(body, term)
};
let arg = if let Some(next_tail_name) = next_tail_name { let arg = if let Some(next_tail_name) = next_tail_name {
Term::Apply { Term::Apply {
@ -3619,7 +3547,7 @@ impl<'a> CodeGenerator<'a> {
.into(), .into(),
} }
} else if tipo.is_list() { } else if tipo.is_list() {
todo!() unreachable!()
} else { } else {
Term::Apply { Term::Apply {
function: DefaultFunction::EqualsInteger.into(), function: DefaultFunction::EqualsInteger.into(),
@ -3646,6 +3574,73 @@ impl<'a> CodeGenerator<'a> {
arg_stack.push(term); arg_stack.push(term);
} }
Air::ListClauseGuard {
tail_name,
next_tail_name,
inverse,
..
} => {
// discard to pop off
let _ = arg_stack.pop().unwrap();
// the body to be run if the clause matches
// the next branch in the when expression
let mut term = arg_stack.pop().unwrap();
term = if let Some(next_tail_name) = next_tail_name {
Term::Apply {
function: Term::Lambda {
parameter_name: Name {
text: next_tail_name,
unique: 0.into(),
},
body: term.into(),
}
.into(),
argument: Term::Apply {
function: Term::Builtin(DefaultFunction::TailList).force_wrap().into(),
argument: Term::Var(Name {
text: tail_name.clone(),
unique: 0.into(),
})
.into(),
}
.into(),
}
} else {
term
};
if !inverse {
term = choose_list(
Term::Var(Name {
text: tail_name,
unique: 0.into(),
}),
Term::Delay(term.into()),
Term::Var(Name {
text: "__other_clauses_delayed".to_string(),
unique: 0.into(),
}),
)
.force_wrap();
} else {
term = choose_list(
Term::Var(Name {
text: tail_name,
unique: 0.into(),
}),
Term::Var(Name {
text: "__other_clauses_delayed".to_string(),
unique: 0.into(),
}),
Term::Delay(term.into()),
)
.force_wrap();
}
arg_stack.push(term);
}
Air::Finally { .. } => { Air::Finally { .. } => {
let _clause = arg_stack.pop().unwrap(); let _clause = arg_stack.pop().unwrap();
} }