Skip to content

Commit e31f41f

Browse files
authored
fix: add more readable error for missing argument in toml (#971)
* feat(nargo): add more readable error for when users miss an argument * chore: clippy fix
1 parent c60f545 commit e31f41f

File tree

2 files changed

+40
-19
lines changed

2 files changed

+40
-19
lines changed

crates/noirc_abi/src/errors.rs

+2
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ pub enum InputParserError {
1414
DuplicateVariableName(String),
1515
#[error("cannot parse a string toml type into {0:?}")]
1616
AbiTypeMismatch(AbiType),
17+
#[error("Expected argument `{0}`, but none was found")]
18+
MissingArgument(String),
1719
}
1820

1921
impl From<toml::ser::Error> for InputParserError {

crates/noirc_abi/src/input_parser/toml.rs

+38-19
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,29 @@ pub(crate) fn parse_toml(
1616
// When parsing the toml map we recursively go through each field to enable struct inputs.
1717
// To match this map with the correct abi type we reorganize our abi by parameter name in a BTreeMap, while the struct fields
1818
// in the abi are already stored in a BTreeMap.
19-
let mut abi_map = abi.to_btree_map();
20-
if let Some(return_type) = &abi.return_type {
21-
abi_map.insert(MAIN_RETURN_NAME.to_owned(), return_type.to_owned());
22-
}
19+
let abi_map = abi.to_btree_map();
2320

2421
// Convert arguments to field elements.
25-
try_btree_map(data, |(key, value)| {
26-
InputValue::try_from_toml(value, &abi_map[&key]).map(|input_value| (key, input_value))
27-
})
22+
let mut parsed_inputs = try_btree_map(abi_map, |(arg_name, abi_type)| {
23+
// Check that toml contains a value for each argument in the ABI.
24+
let value = data
25+
.get(&arg_name)
26+
.ok_or_else(|| InputParserError::MissingArgument(arg_name.clone()))?;
27+
InputValue::try_from_toml(value.clone(), &abi_type, &arg_name)
28+
.map(|input_value| (arg_name, input_value))
29+
})?;
30+
31+
// If the toml file also includes a return value then we parse it as well.
32+
// This isn't required as the prover calculates the return value itself.
33+
if let (Some(return_type), Some(toml_return_value)) =
34+
(&abi.return_type, data.get(MAIN_RETURN_NAME))
35+
{
36+
let return_value =
37+
InputValue::try_from_toml(toml_return_value.clone(), return_type, MAIN_RETURN_NAME)?;
38+
parsed_inputs.insert(MAIN_RETURN_NAME.to_owned(), return_value);
39+
}
40+
41+
Ok(parsed_inputs)
2842
}
2943

3044
pub(crate) fn serialize_to_toml(
@@ -83,6 +97,7 @@ impl InputValue {
8397
fn try_from_toml(
8498
value: TomlTypes,
8599
param_type: &AbiType,
100+
arg_name: &str,
86101
) -> Result<InputValue, InputParserError> {
87102
let input_value = match value {
88103
TomlTypes::String(string) => match param_type {
@@ -128,18 +143,22 @@ impl InputValue {
128143
InputValue::Vec(array_elements)
129144
}
130145

131-
TomlTypes::Table(table) => {
132-
let fields = match param_type {
133-
AbiType::Struct { fields } => fields,
134-
_ => return Err(InputParserError::AbiTypeMismatch(param_type.clone())),
135-
};
136-
let native_table = try_btree_map(table, |(key, value)| {
137-
InputValue::try_from_toml(value, &fields[&key])
138-
.map(|input_value| (key, input_value))
139-
})?;
140-
141-
InputValue::Struct(native_table)
142-
}
146+
TomlTypes::Table(table) => match param_type {
147+
AbiType::Struct { fields } => {
148+
let native_table = try_btree_map(fields, |(field_name, abi_type)| {
149+
// Check that toml contains a value for each field of the struct.
150+
let field_id = format!("{arg_name}.{field_name}");
151+
let value = table
152+
.get(field_name)
153+
.ok_or_else(|| InputParserError::MissingArgument(field_id.clone()))?;
154+
InputValue::try_from_toml(value.clone(), abi_type, &field_id)
155+
.map(|input_value| (field_name.to_string(), input_value))
156+
})?;
157+
158+
InputValue::Struct(native_table)
159+
}
160+
_ => return Err(InputParserError::AbiTypeMismatch(param_type.clone())),
161+
},
143162
};
144163

145164
Ok(input_value)

0 commit comments

Comments
 (0)