add assert and record

Record is a more efficient air for making records
Assert guarantees a custom is of a certain variant.
This commit is contained in:
Kasey White 2023-01-13 02:46:02 -05:00 committed by Lucas
parent 1721c3945b
commit 7b023911af
4 changed files with 212 additions and 32 deletions

View File

@ -59,7 +59,6 @@ pub enum Air {
Call {
scope: Vec<u64>,
count: usize,
tipo: Arc<Type>,
},
Builtin {
@ -82,6 +81,7 @@ pub enum Air {
Assert {
scope: Vec<u64>,
constr_index: usize,
},
DefineFunc {
@ -155,13 +155,10 @@ pub enum Air {
scope: Vec<u64>,
},
Constr {
scope: Vec<u64>,
count: usize,
},
Fields {
Record {
scope: Vec<u64>,
constr_index: usize,
constr_type: Arc<Type>,
count: usize,
},
@ -240,7 +237,7 @@ impl Air {
| Air::Builtin { scope, .. }
| Air::BinOp { scope, .. }
| Air::Assignment { scope, .. }
| Air::Assert { scope }
| Air::Assert { scope, .. }
| Air::DefineFunc { scope, .. }
| Air::Lam { scope, .. }
| Air::When { scope, .. }
@ -251,8 +248,7 @@ impl Air {
| Air::Discard { scope }
| Air::Finally { scope }
| Air::If { scope, .. }
| Air::Constr { scope, .. }
| Air::Fields { scope, .. }
| Air::Record { scope, .. }
| Air::RecordAccess { scope, .. }
| Air::FieldsExpose { scope, .. }
| Air::Tuple { scope, .. }

View File

@ -1123,15 +1123,6 @@ pub fn monomorphize(
}
// TODO check on assignment if type is needed
Air::Assignment { .. } => {}
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::When {
scope,
tipo,
@ -1227,6 +1218,26 @@ pub fn monomorphize(
needs_variant = true;
}
}
Air::Record {
scope,
constr_index,
constr_type,
count,
} => {
if constr_type.is_generic() {
let mut constr_type = constr_type.clone();
find_generics_to_replace(&mut constr_type, &generic_types);
new_air[index] = Air::Record {
scope,
constr_type,
constr_index,
count,
};
needs_variant = true;
}
}
Air::RecordAccess {
scope,
index: record_index,
@ -1454,11 +1465,10 @@ pub fn handle_recursion_ir(
let current_call = recursion_ir[index - 1].clone();
match current_call {
Air::Call { scope, count, tipo } => {
Air::Call { scope, count } => {
recursion_ir[index - 1] = Air::Call {
scope,
count: count + 1,
tipo,
}
}
_ => unreachable!(),

View File

@ -210,10 +210,39 @@ impl<'a> CodeGenerator<'a> {
TypedExpr::Call {
fun, args, tipo, ..
} => {
if let Some(data_type) = self.lookup_data_type_by_tipo(tipo) {
if let TypedExpr::Var { constructor, .. } = &**fun {
if let ValueConstructorVariant::Record {
name: constr_name, ..
} = &constructor.variant
{
let (constr_index, _) = data_type
.constructors
.iter()
.enumerate()
.find(|(_, dt)| &dt.name == constr_name)
.unwrap();
ir_stack.push(Air::Record {
scope: scope.clone(),
constr_index,
constr_type: constructor.tipo.clone(),
count: args.len(),
});
for arg in args {
let mut scope = scope.clone();
scope.push(self.id_gen.next());
self.build_ir(&arg.value, ir_stack, scope);
}
return;
}
}
}
ir_stack.push(Air::Call {
scope: scope.clone(),
count: args.len(),
tipo: tipo.clone(),
});
let mut scope_fun = scope.clone();
scope_fun.push(self.id_gen.next());
@ -250,7 +279,6 @@ impl<'a> CodeGenerator<'a> {
tipo,
..
} => {
let mut define_vec: Vec<Air> = vec![];
let mut value_vec: Vec<Air> = vec![];
let mut pattern_vec: Vec<Air> = vec![];
@ -268,7 +296,6 @@ impl<'a> CodeGenerator<'a> {
scope,
);
ir_stack.append(&mut define_vec);
ir_stack.append(&mut pattern_vec);
}
TypedExpr::When {
@ -1405,12 +1432,81 @@ impl<'a> CodeGenerator<'a> {
}
Pattern::VarUsage { .. } => todo!(),
Pattern::Assign { .. } => todo!(),
Pattern::Discard { .. } => {}
Pattern::Discard { .. } => {
pattern_vec.push(Air::Assignment {
name: "_".to_string(),
scope,
});
pattern_vec.append(value_vec);
}
list @ Pattern::List { .. } => {
self.pattern_ir(list, pattern_vec, value_vec, tipo, scope);
}
Pattern::Constructor { .. } => {
self.pattern_ir(pattern, pattern_vec, value_vec, tipo, scope);
Pattern::Constructor {
name: constr_name,
tipo,
..
} => {
let data_type = self.lookup_data_type_by_tipo(tipo);
let (index, _) = data_type
.unwrap()
.constructors
.iter()
.enumerate()
.find(|(_, dt)| &dt.name == constr_name)
.unwrap();
match kind {
AssignmentKind::Let => {
self.pattern_ir(pattern, pattern_vec, value_vec, tipo, scope);
}
AssignmentKind::Assert => {
let name_id = self.id_gen.next();
pattern_vec.push(Air::Lam {
scope: scope.clone(),
name: format!("__constr_{}", name_id),
});
pattern_vec.append(value_vec);
pattern_vec.push(Air::Assert {
scope: scope.clone(),
constr_index: index,
});
pattern_vec.push(Air::Var {
scope: scope.clone(),
constructor: ValueConstructor::public(
tipo.clone(),
ValueConstructorVariant::LocalVariable {
location: Span::empty(),
},
),
name: format!("__constr_{}", name_id),
variant_name: String::new(),
});
self.pattern_ir(
pattern,
pattern_vec,
&mut vec![Air::Var {
scope: scope.clone(),
constructor: ValueConstructor::public(
tipo.clone(),
ValueConstructorVariant::LocalVariable {
location: Span::empty(),
},
),
name: format!("__constr_{}", name_id),
variant_name: String::new(),
}],
tipo,
scope,
);
}
AssignmentKind::Check => todo!(),
}
}
Pattern::Tuple { .. } => {
self.pattern_ir(pattern, pattern_vec, value_vec, tipo, scope);
@ -2959,8 +3055,31 @@ impl<'a> CodeGenerator<'a> {
arg_stack.push(term);
}
Air::Assert { .. } => {
todo!()
Air::Assert { constr_index, .. } => {
let constr = arg_stack.pop().unwrap();
let mut term = arg_stack.pop().unwrap();
let trace_error = apply_wrap(
apply_wrap(
Term::Builtin(DefaultFunction::Trace).force_wrap(),
Term::Constant(UplcConstant::String("Assert Failed".to_string())),
),
Term::Delay(Term::Error.into()),
)
.force_wrap();
let condition = apply_wrap(
apply_wrap(
DefaultFunction::EqualsInteger.into(),
Term::Constant(UplcConstant::Integer(constr_index as i128)),
),
constr_index_exposer(constr),
);
term = delayed_if_else(condition, term, trace_error);
arg_stack.push(term);
}
Air::DefineFunc {
func_name,
@ -3382,8 +3501,59 @@ impl<'a> CodeGenerator<'a> {
arg_stack.push(term);
}
Air::Constr { .. } => todo!(),
Air::Fields { .. } => todo!(),
Air::Record {
constr_index,
constr_type,
count,
..
} => {
let mut arg_vec = vec![];
for _ in 0..count {
arg_vec.push(arg_stack.pop().unwrap());
}
let mut term = Term::Constant(UplcConstant::ProtoList(UplcType::Data, vec![]));
for (index, arg) in arg_vec.iter().enumerate().rev() {
term = apply_wrap(
apply_wrap(
Term::Builtin(DefaultFunction::MkCons).force_wrap(),
convert_type_to_data(
arg.clone(),
&constr_type.arg_types().unwrap()[index],
),
),
term,
);
}
term = apply_wrap(
apply_wrap(
DefaultFunction::ConstrData.into(),
Term::Constant(UplcConstant::Integer(constr_index as i128)),
),
term,
);
if arg_vec.iter().all(|item| matches!(item, Term::Constant(_))) {
let mut program: Program<Name> = Program {
version: (1, 0, 0),
term,
};
let mut interner = Interner::new();
interner.program(&mut program);
let eval_program: Program<NamedDeBruijn> = program.try_into().unwrap();
let evaluated_term: Term<NamedDeBruijn> =
eval_program.eval(ExBudget::default()).0.unwrap();
term = evaluated_term.try_into().unwrap();
}
arg_stack.push(term);
}
Air::RecordAccess { index, tipo, .. } => {
let constr = arg_stack.pop().unwrap();

View File

@ -7,10 +7,14 @@ pub type Car{
}
// test update_owner2_should_fail(){
// let initial_car: Data = Ford{remote_connect: #[], owner: #[], wheels: 4, truck_bed_limit: 10000}
// assert Honda{ owner, ..} = 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
owner == #[]
}