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:
parent
1721c3945b
commit
7b023911af
|
@ -59,7 +59,6 @@ pub enum Air {
|
||||||
Call {
|
Call {
|
||||||
scope: Vec<u64>,
|
scope: Vec<u64>,
|
||||||
count: usize,
|
count: usize,
|
||||||
tipo: Arc<Type>,
|
|
||||||
},
|
},
|
||||||
|
|
||||||
Builtin {
|
Builtin {
|
||||||
|
@ -82,6 +81,7 @@ pub enum Air {
|
||||||
|
|
||||||
Assert {
|
Assert {
|
||||||
scope: Vec<u64>,
|
scope: Vec<u64>,
|
||||||
|
constr_index: usize,
|
||||||
},
|
},
|
||||||
|
|
||||||
DefineFunc {
|
DefineFunc {
|
||||||
|
@ -155,13 +155,10 @@ pub enum Air {
|
||||||
scope: Vec<u64>,
|
scope: Vec<u64>,
|
||||||
},
|
},
|
||||||
|
|
||||||
Constr {
|
Record {
|
||||||
scope: Vec<u64>,
|
|
||||||
count: usize,
|
|
||||||
},
|
|
||||||
|
|
||||||
Fields {
|
|
||||||
scope: Vec<u64>,
|
scope: Vec<u64>,
|
||||||
|
constr_index: usize,
|
||||||
|
constr_type: Arc<Type>,
|
||||||
count: usize,
|
count: usize,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -240,7 +237,7 @@ impl Air {
|
||||||
| Air::Builtin { scope, .. }
|
| Air::Builtin { scope, .. }
|
||||||
| Air::BinOp { scope, .. }
|
| Air::BinOp { scope, .. }
|
||||||
| Air::Assignment { scope, .. }
|
| Air::Assignment { scope, .. }
|
||||||
| Air::Assert { scope }
|
| Air::Assert { scope, .. }
|
||||||
| Air::DefineFunc { scope, .. }
|
| Air::DefineFunc { scope, .. }
|
||||||
| Air::Lam { scope, .. }
|
| Air::Lam { scope, .. }
|
||||||
| Air::When { scope, .. }
|
| Air::When { scope, .. }
|
||||||
|
@ -251,8 +248,7 @@ impl Air {
|
||||||
| Air::Discard { scope }
|
| Air::Discard { scope }
|
||||||
| Air::Finally { scope }
|
| Air::Finally { scope }
|
||||||
| Air::If { scope, .. }
|
| Air::If { scope, .. }
|
||||||
| Air::Constr { scope, .. }
|
| Air::Record { scope, .. }
|
||||||
| Air::Fields { scope, .. }
|
|
||||||
| Air::RecordAccess { scope, .. }
|
| Air::RecordAccess { scope, .. }
|
||||||
| Air::FieldsExpose { scope, .. }
|
| Air::FieldsExpose { scope, .. }
|
||||||
| Air::Tuple { scope, .. }
|
| Air::Tuple { scope, .. }
|
||||||
|
|
|
@ -1123,15 +1123,6 @@ pub fn monomorphize(
|
||||||
}
|
}
|
||||||
// TODO check on assignment if type is needed
|
// TODO check on assignment if type is needed
|
||||||
Air::Assignment { .. } => {}
|
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 {
|
Air::When {
|
||||||
scope,
|
scope,
|
||||||
tipo,
|
tipo,
|
||||||
|
@ -1227,6 +1218,26 @@ pub fn monomorphize(
|
||||||
needs_variant = true;
|
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 {
|
Air::RecordAccess {
|
||||||
scope,
|
scope,
|
||||||
index: record_index,
|
index: record_index,
|
||||||
|
@ -1454,11 +1465,10 @@ 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, tipo } => {
|
Air::Call { scope, count } => {
|
||||||
recursion_ir[index - 1] = Air::Call {
|
recursion_ir[index - 1] = Air::Call {
|
||||||
scope,
|
scope,
|
||||||
count: count + 1,
|
count: count + 1,
|
||||||
tipo,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
|
|
|
@ -210,10 +210,39 @@ impl<'a> CodeGenerator<'a> {
|
||||||
TypedExpr::Call {
|
TypedExpr::Call {
|
||||||
fun, args, tipo, ..
|
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 {
|
ir_stack.push(Air::Call {
|
||||||
scope: scope.clone(),
|
scope: scope.clone(),
|
||||||
count: args.len(),
|
count: args.len(),
|
||||||
tipo: tipo.clone(),
|
|
||||||
});
|
});
|
||||||
let mut scope_fun = scope.clone();
|
let mut scope_fun = scope.clone();
|
||||||
scope_fun.push(self.id_gen.next());
|
scope_fun.push(self.id_gen.next());
|
||||||
|
@ -250,7 +279,6 @@ impl<'a> CodeGenerator<'a> {
|
||||||
tipo,
|
tipo,
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
let mut define_vec: Vec<Air> = vec![];
|
|
||||||
let mut value_vec: Vec<Air> = vec![];
|
let mut value_vec: Vec<Air> = vec![];
|
||||||
let mut pattern_vec: Vec<Air> = vec![];
|
let mut pattern_vec: Vec<Air> = vec![];
|
||||||
|
|
||||||
|
@ -268,7 +296,6 @@ impl<'a> CodeGenerator<'a> {
|
||||||
scope,
|
scope,
|
||||||
);
|
);
|
||||||
|
|
||||||
ir_stack.append(&mut define_vec);
|
|
||||||
ir_stack.append(&mut pattern_vec);
|
ir_stack.append(&mut pattern_vec);
|
||||||
}
|
}
|
||||||
TypedExpr::When {
|
TypedExpr::When {
|
||||||
|
@ -1405,13 +1432,82 @@ impl<'a> CodeGenerator<'a> {
|
||||||
}
|
}
|
||||||
Pattern::VarUsage { .. } => todo!(),
|
Pattern::VarUsage { .. } => todo!(),
|
||||||
Pattern::Assign { .. } => 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 { .. } => {
|
list @ Pattern::List { .. } => {
|
||||||
self.pattern_ir(list, pattern_vec, value_vec, tipo, scope);
|
self.pattern_ir(list, pattern_vec, value_vec, tipo, scope);
|
||||||
}
|
}
|
||||||
Pattern::Constructor { .. } => {
|
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);
|
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 { .. } => {
|
Pattern::Tuple { .. } => {
|
||||||
self.pattern_ir(pattern, pattern_vec, value_vec, tipo, scope);
|
self.pattern_ir(pattern, pattern_vec, value_vec, tipo, scope);
|
||||||
}
|
}
|
||||||
|
@ -2959,8 +3055,31 @@ impl<'a> CodeGenerator<'a> {
|
||||||
|
|
||||||
arg_stack.push(term);
|
arg_stack.push(term);
|
||||||
}
|
}
|
||||||
Air::Assert { .. } => {
|
Air::Assert { constr_index, .. } => {
|
||||||
todo!()
|
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 {
|
Air::DefineFunc {
|
||||||
func_name,
|
func_name,
|
||||||
|
@ -3382,8 +3501,59 @@ impl<'a> CodeGenerator<'a> {
|
||||||
|
|
||||||
arg_stack.push(term);
|
arg_stack.push(term);
|
||||||
}
|
}
|
||||||
Air::Constr { .. } => todo!(),
|
Air::Record {
|
||||||
Air::Fields { .. } => todo!(),
|
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, .. } => {
|
Air::RecordAccess { index, tipo, .. } => {
|
||||||
let constr = arg_stack.pop().unwrap();
|
let constr = arg_stack.pop().unwrap();
|
||||||
|
|
||||||
|
|
|
@ -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(){
|
test update_owner1(){
|
||||||
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}
|
||||||
assert Ford{ owner, ..} = initial_car
|
assert Ford{ owner, ..} = initial_car
|
||||||
owner == #[]
|
owner == #[]
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue