Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 31 additions & 1 deletion tooling/nargo_cli/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ fn main() -> Result<(), String> {

generate_minimal_execution_success_tests(&mut test_file, &test_dir);
generate_interpret_execution_success_tests(&mut test_file, &test_dir);
generate_interpret_execution_failure_tests(&mut test_file, &test_dir);

generate_fuzzing_failure_tests(&mut test_file, &test_dir);

Expand Down Expand Up @@ -120,9 +121,12 @@ const TESTS_WITH_EXPECTED_WARNINGS: [&str; 5] = [

/// `nargo interpret` ignored tests, either because they don't currently work or
/// because they are too slow to run.
const IGNORED_INTERPRET_EXECUTION_TESTS: [&str; 1] = [
const IGNORED_INTERPRET_EXECUTION_TESTS: [&str; 2] = [
// slow
"regression_4709",
// Doesn't match Brillig, but the expected ref-count of 5 has comments which
// suggest it's not exactly clear why we get that exact value anyway.
"reference_counts_inliner_max",
];

/// `nargo execute --minimal-ssa` ignored tests
Expand Down Expand Up @@ -737,6 +741,32 @@ fn generate_interpret_execution_success_tests(test_file: &mut File, test_data_di
writeln!(test_file, "}}").unwrap();
}

fn generate_interpret_execution_failure_tests(test_file: &mut File, test_data_dir: &Path) {
let test_type = "execution_failure";
let test_cases = read_test_cases(test_data_dir, test_type);

writeln!(
test_file,
"mod interpret_{test_type} {{
use super::*;
"
)
.unwrap();
for (test_name, test_dir) in test_cases {
let test_dir = test_dir.display();

generate_test_cases(
test_file,
&test_name,
&test_dir,
"interpret",
"interpret_execution_failure(nargo);",
&MatrixConfig { vary_brillig: true, ..Default::default() },
);
}
writeln!(test_file, "}}").unwrap();
}

/// Run integration tests with the `--minimal-ssa` option and check that the return
/// value matches the expectations. This also enables `--force-brillig` since `--minimal-ssa`
/// is only valid when all functions are unconstrained.
Expand Down
26 changes: 20 additions & 6 deletions tooling/nargo_cli/src/cli/interpret_cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ pub(crate) fn run(args: InterpretCommand, workspace: Workspace) -> Result<(), Cl

let opts = args.compile_options.as_ssa_options(PathBuf::new());
let ssa_passes = primary_passes(&opts);
let mut is_ok = true;

for package in binary_packages {
let ssa_options =
Expand Down Expand Up @@ -132,7 +133,7 @@ pub(crate) fn run(args: InterpretCommand, workspace: Workspace) -> Result<(), Cl
let file_manager =
if args.compile_options.with_ssa_locations { Some(&file_manager) } else { None };

print_and_interpret_ssa(
is_ok &= print_and_interpret_ssa(
ssa_options,
&args.ssa_pass,
&mut ssa,
Expand All @@ -155,7 +156,7 @@ pub(crate) fn run(args: InterpretCommand, workspace: Workspace) -> Result<(), Cl
.run(ssa)
.map_err(|e| CliError::Generic(format!("failed to run SSA pass {msg}: {e}")))?;

print_and_interpret_ssa(
is_ok &= print_and_interpret_ssa(
ssa_options,
&args.ssa_pass,
&mut ssa,
Expand All @@ -167,7 +168,11 @@ pub(crate) fn run(args: InterpretCommand, workspace: Workspace) -> Result<(), Cl
)?;
}
}
Ok(())
if is_ok {
Ok(())
} else {
Err(CliError::Generic("The interpreter encountered an error on one or more passes.".into()))
}
}

/// Compile the source code into the monomorphized AST, which is one step before SSA passes.
Expand Down Expand Up @@ -237,14 +242,20 @@ fn print_ssa(options: &SsaEvaluatorOptions, ssa: &mut Ssa, msg: &str, fm: Option
}
}

/// Interpret the SSA if it's part of the selected passes.
///
/// The return value is:
/// * `Ok(true)` if the interpretation was successful, or it was skipped.
/// * `Ok(false)` if the interpreter returned an error, but we didn't have any expectation.
/// * `Err(_)` if the returned result did not match the expectation.
fn interpret_ssa(
passes_to_interpret: &[String],
ssa: &Ssa,
msg: &str,
args: &[Value],
return_value: &Option<Vec<Value>>,
options: InterpreterOptions,
) -> Result<(), CliError> {
) -> Result<bool, CliError> {
if passes_to_interpret.is_empty() || msg_matches(passes_to_interpret, msg) {
// We need to give a fresh copy of arrays each time, because the shared structures are modified.
let args = Value::snapshot_args(args);
Expand All @@ -258,6 +269,7 @@ fn interpret_ssa(
println!("--- Interpreter result after {msg}:\nErr({err})\n---");
}
}
let is_ok = result.is_ok();
if let Some(return_value) = return_value {
let result = result.expect("Expected a non-error result");
if &result != return_value {
Expand All @@ -269,8 +281,10 @@ fn interpret_ssa(
return Err(CliError::Generic(error));
}
}
Ok(is_ok)
} else {
Ok(true)
}
Ok(())
}

#[allow(clippy::too_many_arguments)]
Expand All @@ -283,7 +297,7 @@ fn print_and_interpret_ssa(
return_value: &Option<Vec<Value>>,
interpreter_options: InterpreterOptions,
fm: Option<&FileManager>,
) -> Result<(), CliError> {
) -> Result<bool, CliError> {
print_ssa(options, ssa, msg, fm);
interpret_ssa(passes_to_interpret, ssa, msg, args, return_value, interpreter_options)
}
Expand Down
4 changes: 4 additions & 0 deletions tooling/nargo_cli/tests/execute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,10 @@ mod tests {
nargo.assert().success();
}

fn interpret_execution_failure(mut nargo: Command) {
nargo.assert().failure();
}

fn nargo_expand_execute(test_program_dir: PathBuf) {
// First run `nargo execute` on the original code to get the output
let mut nargo = Command::cargo_bin("nargo").unwrap();
Expand Down
3 changes: 2 additions & 1 deletion tooling/ssa_cli/src/cli/interpret_cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ pub(super) fn run(args: InterpretCommand, ssa: Ssa) -> eyre::Result<()> {
println_to_stdout!("--- Interpreter result:\nErr({err})\n---");
}
}
let is_ok = result.is_ok();

if let Some(return_value) = ssa_return {
let return_value_as_string = vecmap(&return_value, ToString::to_string).join(", ");
Expand All @@ -89,7 +90,7 @@ pub(super) fn run(args: InterpretCommand, ssa: Ssa) -> eyre::Result<()> {
}
}

Ok(())
if is_ok { Ok(()) } else { bail!("The interpreter encountered an error.") }
}

/// Derive an ABI description from the SSA parameters.
Expand Down
Loading