covered type mismatch in constant inputs

This commit is contained in:
damirka 2021-03-16 16:32:55 +03:00
parent a516f36e4f
commit 40f4b1cb65
9 changed files with 128 additions and 64 deletions

View File

@ -23,7 +23,7 @@ use leo_input::{
#[derive(Clone, PartialEq, Eq)]
pub struct Input {
name: String,
pub program_input: ProgramInput,
program_input: ProgramInput,
program_state: ProgramState,
}

View File

@ -103,6 +103,12 @@ impl FunctionError {
FunctionError::Error(FormattedError::new_from_span(message, span))
}
pub fn input_type_mismatch(expected: String, actual: String, variable: String, span: &Span) -> Self {
let message = format!("Expected {} to be {} not {}", variable, expected, actual);
Self::new_from_span(message, span)
}
pub fn invalid_array(actual: String, span: &Span) -> Self {
let message = format!("Expected function input array, found `{}`", actual);

View File

@ -76,73 +76,110 @@ impl<'a, F: PrimeField, G: GroupType<F>> ConstrainedProgram<'a, F, G> {
input_option: Option<InputValue>,
span: &Span,
) -> Result<ConstrainedValue<'a, F, G>, FunctionError> {
let value = input_option.unwrap();
let input = input_option.ok_or_else(|| FunctionError::input_not_found(name.to_string(), span))?;
Ok(match value {
InputValue::Address(value) => ConstrainedValue::Address(Address::constant(value, span)?),
InputValue::Boolean(value) => ConstrainedValue::Boolean(Boolean::constant(value)),
InputValue::Field(value) => ConstrainedValue::Field(FieldType::constant(value, span)?),
InputValue::Group(value) => ConstrainedValue::Group(G::constant(&value.into(), span)?),
InputValue::Integer(integer_type, value) => {
let integer = IntegerType::from(integer_type);
let const_int = match integer {
IntegerType::U8 => ConstInt::U8(value.parse::<u8>().unwrap()),
IntegerType::U16 => ConstInt::U16(value.parse::<u16>().unwrap()),
IntegerType::U32 => ConstInt::U32(value.parse::<u32>().unwrap()),
IntegerType::U64 => ConstInt::U64(value.parse::<u64>().unwrap()),
IntegerType::U128 => ConstInt::U128(value.parse::<u128>().unwrap()),
match type_ {
Type::Address => match input {
InputValue::Address(addr) => Ok(ConstrainedValue::Address(Address::constant(addr, span)?)),
_ => Err(FunctionError::input_type_mismatch(
type_.to_string(),
input.to_string(),
name.to_string(),
span,
)),
},
Type::Boolean => match input {
InputValue::Boolean(value) => Ok(ConstrainedValue::Boolean(Boolean::constant(value))),
_ => Err(FunctionError::input_not_found(name.to_string(), span)),
},
Type::Field => match input {
InputValue::Field(value) => Ok(ConstrainedValue::Field(FieldType::constant(value, span)?)),
_ => Err(FunctionError::input_type_mismatch(
type_.to_string(),
input.to_string(),
name.to_string(),
span,
)),
},
Type::Group => match input {
InputValue::Group(value) => Ok(ConstrainedValue::Group(G::constant(&value.into(), span)?)),
_ => Err(FunctionError::input_type_mismatch(
type_.to_string(),
input.to_string(),
name.to_string(),
span,
)),
},
Type::Integer(integer_type) => match input {
InputValue::Integer(_, value) => {
let const_int = match integer_type {
IntegerType::U8 => ConstInt::U8(value.parse::<u8>().unwrap()),
IntegerType::U16 => ConstInt::U16(value.parse::<u16>().unwrap()),
IntegerType::U32 => ConstInt::U32(value.parse::<u32>().unwrap()),
IntegerType::U64 => ConstInt::U64(value.parse::<u64>().unwrap()),
IntegerType::U128 => ConstInt::U128(value.parse::<u128>().unwrap()),
IntegerType::I8 => ConstInt::I8(value.parse::<i8>().unwrap()),
IntegerType::I16 => ConstInt::I16(value.parse::<i16>().unwrap()),
IntegerType::I32 => ConstInt::I32(value.parse::<i32>().unwrap()),
IntegerType::I64 => ConstInt::I64(value.parse::<i64>().unwrap()),
IntegerType::I128 => ConstInt::I128(value.parse::<i128>().unwrap()),
};
IntegerType::I8 => ConstInt::I8(value.parse::<i8>().unwrap()),
IntegerType::I16 => ConstInt::I16(value.parse::<i16>().unwrap()),
IntegerType::I32 => ConstInt::I32(value.parse::<i32>().unwrap()),
IntegerType::I64 => ConstInt::I64(value.parse::<i64>().unwrap()),
IntegerType::I128 => ConstInt::I128(value.parse::<i128>().unwrap()),
};
ConstrainedValue::Integer(Integer::new(&const_int))
}
InputValue::Array(values) => {
// Get ASG type and array length to compare with provided inputs.
let (type_, arr_len) = if let Type::Array(type_, len) = type_ {
(type_, *len)
} else {
return Err(FunctionError::input_not_found("expected".to_string(), &span));
};
if arr_len != values.len() {
return Err(FunctionError::invalid_input_array_dimensions(
arr_len,
values.len(),
span,
));
Ok(ConstrainedValue::Integer(Integer::new(&const_int)))
}
_ => Err(FunctionError::input_type_mismatch(
type_.to_string(),
input.to_string(),
name.to_string(),
span,
)),
},
Type::Array(type_, arr_len) => match input {
InputValue::Array(values) => {
if *arr_len != values.len() {
return Err(FunctionError::invalid_input_array_dimensions(
*arr_len,
values.len(),
span,
));
}
ConstrainedValue::Array(
values
.iter()
.map(|x| self.constant_main_function_input(_cs, type_, name, Some(x.clone()), span))
.collect::<Result<Vec<_>, _>>()?,
)
}
InputValue::Tuple(values) => {
// Get ASG tuple size and compare it to input tuple size.
let tuple_len = if let Type::Tuple(types) = type_ {
types.len()
} else {
return Err(FunctionError::tuple_size_mismatch(0, values.len(), span));
};
if values.len() != tuple_len {
return Err(FunctionError::tuple_size_mismatch(tuple_len, values.len(), span));
Ok(ConstrainedValue::Array(
values
.iter()
.map(|x| self.constant_main_function_input(_cs, type_, name, Some(x.clone()), span))
.collect::<Result<Vec<_>, _>>()?,
))
}
_ => Err(FunctionError::input_type_mismatch(
type_.to_string(),
input.to_string(),
name.to_string(),
span,
)),
},
Type::Tuple(types) => match input {
InputValue::Tuple(values) => {
if values.len() != types.len() {
return Err(FunctionError::tuple_size_mismatch(types.len(), values.len(), span));
}
ConstrainedValue::Tuple(
values
.iter()
.map(|x| self.constant_main_function_input(_cs, type_, name, Some(x.clone()), span))
.collect::<Result<Vec<_>, _>>()?,
)
}
})
Ok(ConstrainedValue::Tuple(
values
.iter()
.map(|x| self.constant_main_function_input(_cs, type_, name, Some(x.clone()), span))
.collect::<Result<Vec<_>, _>>()?,
))
}
_ => Err(FunctionError::input_type_mismatch(
type_.to_string(),
input.to_string(),
name.to_string(),
span,
)),
},
_ => unimplemented!("main function input not implemented for type {}", type_),
}
}
}

View File

@ -37,7 +37,11 @@ impl<'a, F: PrimeField, G: GroupType<F>> ConstrainedProgram<'a, F, G> {
match input_value {
Some(InputValue::Tuple(values)) => {
// Allocate each value in the tuple
if values.len() != types.len() {
return Err(FunctionError::tuple_size_mismatch(types.len(), values.len(), span));
}
// Allocate each value in the tuple.
for (i, (value, type_)) in values.into_iter().zip(types.iter()).enumerate() {
let value_name = format!("{}_{}", &name, &i.to_string());

View File

@ -0,0 +1,2 @@
[main]
x: (u8, bool) = (10, true); // wrong size here; main expects (u8, bool, u8)

View File

@ -0,0 +1,3 @@
function main(x: (u8, bool, u8)) {
console.log("x: {}", x);
}

View File

@ -94,6 +94,16 @@ fn test_input_array_dimensions_mismatch() {
expect_fail(program);
}
#[test]
fn test_tuple_size_mismatch() {
let program_string = include_str!("main_tuple_fail.leo");
let input_string = include_str!("input/main_tuple_fail.in");
let program = parse_program_with_input(program_string, input_string).unwrap();
expect_fail(program);
}
#[test]
fn test_field_input() {
let program_string = include_str!("main_field.leo");

View File

@ -0,0 +1,2 @@
[constants]
a: u8 = 10;

View File

@ -1,3 +1,3 @@
function main(x: (u8, bool, u8)) {
function main(const x: (u8, bool, u8)) {
console.log("x: {}", x);
}