Skip to content

Commit 47aec5d

Browse files
chore: regression test #7195 (#7233)
1 parent a995bf2 commit 47aec5d

File tree

8 files changed

+202
-11
lines changed

8 files changed

+202
-11
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
[package]
2+
name = "regression_7195"
3+
type = "bin"
4+
authors = [""]
5+
6+
[dependencies]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
x = "1"
2+
y = "2"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
fn bar(y: Field) {
2+
assert(y != 0);
3+
}
4+
5+
fn foo(x: Field) {
6+
// Safety: test
7+
let y = unsafe { baz(x) };
8+
bar(y);
9+
}
10+
11+
unconstrained fn baz(x: Field) -> Field {
12+
x
13+
}
14+
15+
fn main(x: Field, y: pub Field) {
16+
// Safety: test
17+
let x = unsafe { baz(x) };
18+
foo(x);
19+
foo(y);
20+
assert(x != y);
21+
}

tooling/debugger/src/lib.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,9 @@ pub fn run_repl_session<B: BlackBoxFunctionSolver<FieldElement>>(
1919
solver: &B,
2020
program: CompiledProgram,
2121
initial_witness: WitnessMap<FieldElement>,
22+
raw_source_printing: bool,
2223
) -> Result<Option<WitnessStack<FieldElement>>, NargoError<FieldElement>> {
23-
repl::run(solver, program, initial_witness)
24+
repl::run(solver, program, initial_witness, raw_source_printing)
2425
}
2526

2627
pub fn run_dap_loop<R: Read, W: Write, B: BlackBoxFunctionSolver<FieldElement>>(

tooling/debugger/src/repl.rs

+14-2
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ pub struct ReplDebugger<'a, B: BlackBoxFunctionSolver<FieldElement>> {
3232

3333
// Brillig functions referenced from the ACIR circuits above
3434
unconstrained_functions: &'a [BrilligBytecode<FieldElement>],
35+
36+
// whether to print the source without highlighting, pretty-printing,
37+
// or line numbers
38+
raw_source_printing: bool,
3539
}
3640

3741
impl<'a, B: BlackBoxFunctionSolver<FieldElement>> ReplDebugger<'a, B> {
@@ -41,6 +45,7 @@ impl<'a, B: BlackBoxFunctionSolver<FieldElement>> ReplDebugger<'a, B> {
4145
debug_artifact: &'a DebugArtifact,
4246
initial_witness: WitnessMap<FieldElement>,
4347
unconstrained_functions: &'a [BrilligBytecode<FieldElement>],
48+
raw_source_printing: bool,
4449
) -> Self {
4550
let foreign_call_executor = Box::new(DefaultDebugForeignCallExecutor::from_artifact(
4651
PrintOutput::Stdout,
@@ -68,6 +73,7 @@ impl<'a, B: BlackBoxFunctionSolver<FieldElement>> ReplDebugger<'a, B> {
6873
initial_witness,
6974
last_result,
7075
unconstrained_functions,
76+
raw_source_printing,
7177
}
7278
}
7379

@@ -97,7 +103,11 @@ impl<'a, B: BlackBoxFunctionSolver<FieldElement>> ReplDebugger<'a, B> {
97103
}
98104
}
99105
let locations = self.context.get_source_location_for_debug_location(&location);
100-
print_source_code_location(self.debug_artifact, &locations);
106+
print_source_code_location(
107+
self.debug_artifact,
108+
&locations,
109+
self.raw_source_printing,
110+
);
101111
}
102112
}
103113
}
@@ -125,7 +135,7 @@ impl<'a, B: BlackBoxFunctionSolver<FieldElement>> ReplDebugger<'a, B> {
125135
}
126136
}
127137
let locations = self.context.get_source_location_for_debug_location(debug_location);
128-
print_source_code_location(self.debug_artifact, &locations);
138+
print_source_code_location(self.debug_artifact, &locations, self.raw_source_printing);
129139
}
130140

131141
pub fn show_current_call_stack(&self) {
@@ -427,6 +437,7 @@ pub fn run<B: BlackBoxFunctionSolver<FieldElement>>(
427437
blackbox_solver: &B,
428438
program: CompiledProgram,
429439
initial_witness: WitnessMap<FieldElement>,
440+
raw_source_printing: bool,
430441
) -> Result<Option<WitnessStack<FieldElement>>, NargoError<FieldElement>> {
431442
let circuits = &program.program.functions;
432443
let debug_artifact =
@@ -438,6 +449,7 @@ pub fn run<B: BlackBoxFunctionSolver<FieldElement>>(
438449
debug_artifact,
439450
initial_witness,
440451
unconstrained_functions,
452+
raw_source_printing,
441453
));
442454
let ref_context = &context;
443455

tooling/debugger/src/source_code_printer.rs

+29-5
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,11 @@ struct LocationPrintContext {
3030
// Given a DebugArtifact and an OpcodeLocation, prints all the source code
3131
// locations the OpcodeLocation maps to, with some surrounding context and
3232
// visual aids to highlight the location itself.
33-
pub(super) fn print_source_code_location(debug_artifact: &DebugArtifact, locations: &[Location]) {
33+
pub(super) fn print_source_code_location(
34+
debug_artifact: &DebugArtifact,
35+
locations: &[Location],
36+
raw_source_printing: bool,
37+
) {
3438
let locations = locations.iter();
3539

3640
for loc in locations {
@@ -41,9 +45,11 @@ pub(super) fn print_source_code_location(debug_artifact: &DebugArtifact, locatio
4145
for line in lines {
4246
match line {
4347
PrintedLine::Skip => {}
44-
PrintedLine::Ellipsis { line_number } => print_ellipsis(line_number),
48+
PrintedLine::Ellipsis { line_number } => {
49+
print_ellipsis(line_number, raw_source_printing)
50+
}
4551
PrintedLine::Content { line_number, cursor, content, highlight } => {
46-
print_content(line_number, cursor, content, highlight)
52+
print_content(line_number, cursor, content, highlight, raw_source_printing)
4753
}
4854
}
4955
}
@@ -57,11 +63,29 @@ fn print_location_path(debug_artifact: &DebugArtifact, loc: Location) {
5763
println!("At {}:{line_number}:{column_number}", debug_artifact.name(loc.file).unwrap());
5864
}
5965

60-
fn print_ellipsis(line_number: usize) {
66+
fn print_ellipsis(line_number: usize, raw_source_printing: bool) {
67+
if raw_source_printing {
68+
println!("...");
69+
return;
70+
}
71+
6172
println!("{:>3} {:2} {}", line_number.dimmed(), "", "...".dimmed());
6273
}
6374

64-
fn print_content(line_number: usize, cursor: &str, content: &str, highlight: Option<Range<usize>>) {
75+
fn print_content(
76+
line_number: usize,
77+
cursor: &str,
78+
content: &str,
79+
highlight: Option<Range<usize>>,
80+
raw_source_printing: bool,
81+
) {
82+
if raw_source_printing {
83+
if cursor == "->" && highlight.is_some() {
84+
println!("{}", content);
85+
}
86+
return;
87+
}
88+
6589
match highlight {
6690
Some(highlight) => {
6791
println!(

tooling/debugger/tests/debug.rs

+111
Original file line numberDiff line numberDiff line change
@@ -49,4 +49,115 @@ mod tests {
4949
// Exit the bash session.
5050
dbg_session.send_line("exit").expect("Failed to quit bash session");
5151
}
52+
53+
#[test]
54+
fn debugger_expected_call_stack() {
55+
let nargo_bin =
56+
cargo_bin("nargo").into_os_string().into_string().expect("Cannot parse nargo path");
57+
58+
let timeout_seconds = 30;
59+
let mut dbg_session =
60+
spawn_bash(Some(timeout_seconds * 1000)).expect("Could not start bash session");
61+
62+
let test_program_path = std::path::Path::new(env!("CARGO_MANIFEST_DIR"))
63+
.join("../../test_programs/execution_success/regression_7195");
64+
let test_program_dir = test_program_path.display();
65+
66+
// Start debugger and test that it loads for the given program.
67+
dbg_session
68+
.execute(
69+
&format!(
70+
"{nargo_bin} debug --raw-source-printing true --program-dir {test_program_dir} --force-brillig --expression-width 3"
71+
),
72+
".*\\Starting debugger.*",
73+
)
74+
.expect("Could not start debugger");
75+
76+
let num_steps = 16;
77+
for _ in 1..=num_steps {
78+
// While running the debugger, issue a "next" cmd,
79+
// which should run to the program to the next source line given
80+
// we haven't set any breakpoints.
81+
// ">" is the debugger's prompt, so finding one
82+
// after running "next" indicates that the
83+
// debugger has not panicked for this step.
84+
dbg_session
85+
.send_line("next")
86+
.expect("Debugger panicked while attempting to step through program.");
87+
dbg_session
88+
.exp_string(">")
89+
.expect("Failed while waiting for debugger to step through program.");
90+
}
91+
92+
let mut lines = vec![];
93+
while let Ok(line) = dbg_session.read_line() {
94+
if !(line.starts_with(">next") || line.starts_with("At ") || line.starts_with("...")) {
95+
lines.push(line);
96+
}
97+
}
98+
99+
let lines_expected_to_contain: Vec<&str> = vec![
100+
"> next",
101+
" let x = unsafe { baz(x) };",
102+
"unconstrained fn baz(x: Field) -> Field {",
103+
"> next",
104+
" let x = unsafe { baz(x) };",
105+
"unconstrained fn baz(x: Field) -> Field {",
106+
"> next",
107+
" let x = unsafe { baz(x) };",
108+
"}",
109+
"> next",
110+
" let x = unsafe { baz(x) };",
111+
"> next",
112+
" foo(x);",
113+
"fn foo(x: Field) {",
114+
"> next",
115+
" foo(x);",
116+
"fn foo(x: Field) {",
117+
"> next",
118+
" foo(x);",
119+
" let y = unsafe { baz(x) };",
120+
"unconstrained fn baz(x: Field) -> Field {",
121+
"> next",
122+
" foo(x);",
123+
" let y = unsafe { baz(x) };",
124+
"unconstrained fn baz(x: Field) -> Field {",
125+
"> next",
126+
" foo(x);",
127+
" let y = unsafe { baz(x) };",
128+
"}",
129+
"> next",
130+
" foo(x);",
131+
" let y = unsafe { baz(x) };",
132+
"> next",
133+
" foo(x);",
134+
" bar(y);",
135+
"fn bar(y: Field) {",
136+
"> next",
137+
" foo(x);",
138+
" bar(y);",
139+
"fn bar(y: Field) {",
140+
"> next",
141+
" foo(x);",
142+
" bar(y);",
143+
" assert(y != 0);",
144+
];
145+
146+
for (line, line_expected_to_contain) in lines.into_iter().zip(lines_expected_to_contain) {
147+
let ascii_line: String = line.chars().filter(char::is_ascii).collect();
148+
let line_expected_to_contain = line_expected_to_contain.trim_start();
149+
assert!(
150+
ascii_line.contains(line_expected_to_contain),
151+
"{:?}\ndid not contain\n{:?}",
152+
ascii_line,
153+
line_expected_to_contain,
154+
);
155+
}
156+
157+
// Run the "quit" command
158+
dbg_session.send_line("quit").expect("Failed to quit debugger");
159+
160+
// Exit the bash session.
161+
dbg_session.send_line("exit").expect("Failed to quit bash session");
162+
}
52163
}

tooling/nargo_cli/src/cli/debug_cmd.rs

+17-3
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,10 @@ pub(crate) struct DebugCommand {
4848
/// Disable vars debug instrumentation (enabled by default)
4949
#[clap(long)]
5050
skip_instrumentation: Option<bool>,
51+
52+
/// Raw string printing of source for testing
53+
#[clap(long, hide = true)]
54+
raw_source_printing: Option<bool>,
5155
}
5256

5357
impl WorkspaceCommand for DebugCommand {
@@ -97,6 +101,7 @@ pub(crate) fn run(args: DebugCommand, workspace: Workspace) -> Result<(), CliErr
97101
&args.witness_name,
98102
target_dir,
99103
args.compile_options.pedantic_solving,
104+
args.raw_source_printing.unwrap_or(false),
100105
)
101106
}
102107

@@ -185,14 +190,20 @@ fn run_async(
185190
witness_name: &Option<String>,
186191
target_dir: &PathBuf,
187192
pedantic_solving: bool,
193+
raw_source_printing: bool,
188194
) -> Result<(), CliError> {
189195
use tokio::runtime::Builder;
190196
let runtime = Builder::new_current_thread().enable_all().build().unwrap();
191197

192198
runtime.block_on(async {
193199
println!("[{}] Starting debugger", package.name);
194-
let (return_value, witness_stack) =
195-
debug_program_and_decode(program, package, prover_name, pedantic_solving)?;
200+
let (return_value, witness_stack) = debug_program_and_decode(
201+
program,
202+
package,
203+
prover_name,
204+
pedantic_solving,
205+
raw_source_printing,
206+
)?;
196207

197208
if let Some(solved_witness_stack) = witness_stack {
198209
println!("[{}] Circuit witness successfully solved", package.name);
@@ -220,12 +231,13 @@ fn debug_program_and_decode(
220231
package: &Package,
221232
prover_name: &str,
222233
pedantic_solving: bool,
234+
raw_source_printing: bool,
223235
) -> Result<(Option<InputValue>, Option<WitnessStack<FieldElement>>), CliError> {
224236
// Parse the initial witness values from Prover.toml
225237
let (inputs_map, _) =
226238
read_inputs_from_file(&package.root_dir, prover_name, Format::Toml, &program.abi)?;
227239
let program_abi = program.abi.clone();
228-
let witness_stack = debug_program(program, &inputs_map, pedantic_solving)?;
240+
let witness_stack = debug_program(program, &inputs_map, pedantic_solving, raw_source_printing)?;
229241

230242
match witness_stack {
231243
Some(witness_stack) => {
@@ -244,13 +256,15 @@ pub(crate) fn debug_program(
244256
compiled_program: CompiledProgram,
245257
inputs_map: &InputMap,
246258
pedantic_solving: bool,
259+
raw_source_printing: bool,
247260
) -> Result<Option<WitnessStack<FieldElement>>, CliError> {
248261
let initial_witness = compiled_program.abi.encode(inputs_map, None)?;
249262

250263
noir_debugger::run_repl_session(
251264
&Bn254BlackBoxSolver(pedantic_solving),
252265
compiled_program,
253266
initial_witness,
267+
raw_source_printing,
254268
)
255269
.map_err(CliError::from)
256270
}

0 commit comments

Comments
 (0)