use rustc_hir::def_id::DefId;
use super::contract::Property;
use crate::helpers::mir_scan::CheckpointLocation;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(crate) enum UnknownReason {
SmtTimeout,
Unimplemented,
}
impl UnknownReason {
fn merge(self, other: UnknownReason) -> UnknownReason {
match (self, other) {
(UnknownReason::SmtTimeout, _) | (_, UnknownReason::SmtTimeout) => {
UnknownReason::SmtTimeout
}
_ => UnknownReason::Unimplemented,
}
}
}
#[derive(Clone, Debug, PartialEq)]
pub(crate) enum CheckResult {
ProvedByRule,
ProvedBySmt,
Failed,
Unknown(UnknownReason),
}
impl CheckResult {
pub(crate) fn is_proved(&self) -> bool {
matches!(self, CheckResult::ProvedByRule | CheckResult::ProvedBySmt)
}
pub(crate) fn label(&self) -> &'static str {
match self {
CheckResult::ProvedByRule | CheckResult::ProvedBySmt => "Proved",
CheckResult::Failed => "Failed",
CheckResult::Unknown(UnknownReason::SmtTimeout) => "Unknown (timeout)",
CheckResult::Unknown(UnknownReason::Unimplemented) => "Unknown",
}
}
pub(crate) fn and(self, other: CheckResult) -> CheckResult {
match (self, other) {
(CheckResult::Failed, _) | (_, CheckResult::Failed) => CheckResult::Failed,
(CheckResult::Unknown(a), CheckResult::Unknown(b)) => {
CheckResult::Unknown(a.merge(b))
}
(CheckResult::Unknown(a), _) | (_, CheckResult::Unknown(a)) => CheckResult::Unknown(a),
(CheckResult::ProvedByRule, CheckResult::ProvedByRule) => CheckResult::ProvedByRule,
_ => CheckResult::ProvedBySmt,
}
}
pub(crate) fn or(self, other: CheckResult) -> CheckResult {
match (self, other) {
(CheckResult::ProvedByRule, _) | (_, CheckResult::ProvedByRule) => {
CheckResult::ProvedByRule
}
(CheckResult::ProvedBySmt, _) | (_, CheckResult::ProvedBySmt) => {
CheckResult::ProvedBySmt
}
(CheckResult::Failed, CheckResult::Failed) => CheckResult::Failed,
(CheckResult::Unknown(a), CheckResult::Unknown(b)) => {
CheckResult::Unknown(a.merge(b))
}
(CheckResult::Unknown(a), _) | (_, CheckResult::Unknown(a)) => CheckResult::Unknown(a),
}
}
}
#[derive(Clone, Debug)]
pub(crate) struct PropertyCheckResult<'tcx> {
pub checkpoint: CheckpointLocation,
pub checkpoint_index: usize,
pub path_index: usize,
pub property_index: usize,
pub property: Property<'tcx>,
pub result: CheckResult,
pub diagnostics: Option<String>,
pub path_description: String,
pub callee_name: String,
}
#[derive(Clone, Debug)]
pub(crate) struct VerificationReport<'tcx> {
pub function: DefId,
pub results: Vec<PropertyCheckResult<'tcx>>,
}
impl<'tcx> VerificationReport<'tcx> {
pub(crate) fn new(function: DefId) -> Self {
Self {
function,
results: Vec::new(),
}
}
pub(crate) fn push(&mut self, result: PropertyCheckResult<'tcx>) {
self.results.push(result);
}
pub(crate) fn describe(&self) -> String {
let mut out = String::new();
out.push_str(&format!(
"[rapx::verify::diagnostics] function {:?}: {} check item(s)\n",
self.function,
self.results.len()
));
for (index, result) in self.results.iter().enumerate() {
out.push_str(&format!(
" check #{index}: checkpoint #{}, bb{}, path #{}, property #{} {:?}, result {}\n",
result.checkpoint_index,
result.checkpoint.block.as_usize(),
result.path_index,
result.property_index,
result.property.kind(),
result.result.label()
));
if let Some(diagnostics) = &result.diagnostics {
out.push_str(diagnostics);
if !diagnostics.ends_with('\n') {
out.push('\n');
}
}
}
out
}
}