Skip to content

Commit 2c2145c

Browse files
authored
Use position IDs as Viper line numbers (#1418)
* Use position IDs as Viper line numbers * Add flag to configure number of errors per function * Test reporting of multiple errors
1 parent d3dc999 commit 2c2145c

5 files changed

Lines changed: 105 additions & 3 deletions

File tree

prusti-common/src/vir/to_viper.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,10 @@ impl<'v> ToViper<'v, viper::Position<'v>> for Position {
9393
line = %self.line(), column = %self.column(), id = %self.id()
9494
))]
9595
fn to_viper(&self, _context: Context, ast: &AstFactory<'v>) -> viper::Position<'v> {
96-
ast.identifier_position(self.line(), self.column(), self.id().to_string())
96+
// The line and column of a vir::Position refer to the source Rust program.
97+
// Line and columns in Viper positions have a different semantics, because Silicon
98+
// deduplicates error messages based on them.
99+
ast.identifier_position(self.id() as i32, 0, self.id().to_string())
97100
}
98101
}
99102

@@ -323,8 +326,7 @@ impl<'v> ToViper<'v, viper::Stmt<'v>> for Stmt {
323326
),
324327
pos.to_viper(context, ast),
325328
);
326-
let position =
327-
ast.identifier_position(pos.line(), pos.column(), pos.id().to_string());
329+
let position = pos.to_viper(context, ast);
328330
let apply = ast.apply(wand.to_viper(context, ast), position);
329331
ast.seqn(&[inhale, apply], &[])
330332
}

prusti-server/src/verification_request.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ impl ViperBackendConfig {
3737
let mut verifier_args = config::extra_verifier_args();
3838
match backend {
3939
VerificationBackend::Silicon => {
40+
verifier_args.push(format!(
41+
"--numberOfErrorsToReport={}",
42+
config::num_errors_per_function()
43+
));
4044
if config::use_more_complete_exhale() {
4145
verifier_args.push("--enableMoreCompleteExhale".to_string());
4246
}

prusti-utils/src/config.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ lazy_static::lazy_static! {
129129
settings.set_default("use_new_encoder", true).unwrap();
130130
settings.set_default::<Option<u8>>("number_of_parallel_verifiers", None).unwrap();
131131
settings.set_default::<Option<String>>("min_prusti_version", None).unwrap();
132+
settings.set_default("num_errors_per_function", 1).unwrap();
132133

133134
settings.set_default("print_desugared_specs", false).unwrap();
134135
settings.set_default("print_typeckd_specs", false).unwrap();
@@ -1023,3 +1024,9 @@ pub fn cargo_command() -> String {
10231024
pub fn enable_type_invariants() -> bool {
10241025
read_setting("enable_type_invariants")
10251026
}
1027+
1028+
/// The maximum number of verification errors to report per function. This is only used by the
1029+
/// Silicon backend. A value of 0 means no limit.
1030+
pub fn num_errors_per_function() -> u32 {
1031+
read_setting("num_errors_per_function")
1032+
}

prusti-viper/src/encoder/errors/position_manager.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ impl<'tcx> PositionManager<'tcx>
3737
}
3838
}
3939

40+
/// Registers a new span and returns the corresponding VIR position.
41+
/// The line and column of the VIR position correspond to the start of the given span.
4042
#[tracing::instrument(level = "trace", skip(self), ret)]
4143
pub fn register_span<T: Into<MultiSpan> + Debug>(&mut self, def_id: ProcedureDefId, span: T) -> Position {
4244
let span = span.into();

viper/tests/multiple_errors.rs

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
use std::{sync::Once, vec};
2+
use viper::*;
3+
4+
static INIT: Once = Once::new();
5+
6+
lazy_static::lazy_static! {
7+
static ref VIPER: Viper = Viper::new_for_tests();
8+
}
9+
10+
/// Setup function that is only run once, even if called multiple times.
11+
fn setup() {
12+
INIT.call_once(|| {
13+
env_logger::init();
14+
});
15+
}
16+
17+
fn verify_multiple_errors(backend: viper::VerificationBackend, args: Vec<String>) {
18+
setup();
19+
20+
let verification_context: VerificationContext = VIPER.attach_current_thread();
21+
let ast = verification_context.new_ast_factory();
22+
23+
let pos_1 = ast.identifier_position(123, 0, "pos-id:123");
24+
let pos_1b = ast.identifier_position(1230, 0, "pos-id:1230");
25+
let assertion_1 = ast.assert(
26+
ast.eq_cmp_with_pos(ast.local_var("x", ast.int_type()), ast.int_lit(0), pos_1b),
27+
pos_1,
28+
);
29+
30+
let havoc = ast.local_var_assign(
31+
ast.local_var("x", ast.int_type()),
32+
ast.local_var("v", ast.int_type()),
33+
);
34+
35+
let pos_2 = ast.identifier_position(456, 0, "pos-id:456");
36+
let pos_2b = ast.identifier_position(4560, 0, "pos-id:4560");
37+
let assertion_2 = ast.assert(
38+
ast.eq_cmp_with_pos(ast.local_var("x", ast.int_type()), ast.int_lit(0), pos_2b),
39+
pos_2,
40+
);
41+
42+
let body = ast.seqn(
43+
&[assertion_1, havoc, assertion_2],
44+
&[ast.local_var_decl("x", ast.int_type()).into()],
45+
);
46+
let method = ast.method(
47+
"foo",
48+
&[ast.local_var_decl("v", ast.int_type())],
49+
&[],
50+
&[],
51+
&[],
52+
Some(body),
53+
);
54+
let program = ast.program(&[], &[], &[], &[], &[method]);
55+
56+
let mut verifier =
57+
verification_context.new_verifier_with_default_smt_and_extra_args(backend, args);
58+
59+
let verification_result = verifier.verify(program);
60+
61+
if let VerificationResult::Failure(errors) = verification_result {
62+
assert_eq!(errors.len(), 2);
63+
assert_eq!(
64+
errors[0].full_id,
65+
"assert.failed:assertion.false".to_string()
66+
);
67+
assert_eq!(
68+
errors[1].full_id,
69+
"assert.failed:assertion.false".to_string()
70+
);
71+
assert_eq!(errors[0].offending_pos_id, Some("pos-id:123".to_string()));
72+
assert_eq!(errors[1].offending_pos_id, Some("pos-id:456".to_string()));
73+
} else {
74+
unreachable!("{:?}", verification_result);
75+
}
76+
}
77+
78+
#[test]
79+
fn report_multiple_errors_with_silicon() {
80+
verify_multiple_errors(
81+
viper::VerificationBackend::Silicon,
82+
vec![
83+
"--logLevel=INFO".to_string(),
84+
"--numberOfErrorsToReport=0".to_string(),
85+
],
86+
);
87+
}

0 commit comments

Comments
 (0)