diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index fc8a910aa7d..7da8879a734 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -49,7 +49,7 @@ jobs: shared-key: "shared" - name: Check and report Clippy errors run: | - python ./x.py clippy -- -D warnings + python ./x.py clippy-all # Detect missing dependencies in workspace packages # See: https://stackoverflow.com/a/74293494/2491528 diff --git a/jni-gen/systest/build.rs b/jni-gen/systest/build.rs index 4a690f335f8..b120fd97c4f 100644 --- a/jni-gen/systest/build.rs +++ b/jni-gen/systest/build.rs @@ -29,22 +29,30 @@ fn main() { .use_jar(&asm_jar) .wrap(java_class!("java.lang.Object")) .wrap_all(vec![ - java_class!("java.lang.Integer", vec![ - constructor!("(I)V"), - field!("value"), - method!("compareTo", "(Ljava/lang/Integer;)I"), - ]), - java_class!("java.util.Arrays", vec![ - method!("binarySearch", "([Ljava/lang/Object;Ljava/lang/Object;)I"), - ]), - java_class!("java.lang.Error", vec![ - constructor!("(Ljava/lang/String;)V"), - method!("getMessage"), - field!("detailMessage"), - ]), - java_class!("java.math.BigInteger", vec![ - method!("probablePrime"), - ]), + java_class!( + "java.lang.Integer", + vec![ + constructor!("(I)V"), + field!("value"), + method!("compareTo", "(Ljava/lang/Integer;)I"), + ] + ), + java_class!( + "java.util.Arrays", + vec![method!( + "binarySearch", + "([Ljava/lang/Object;Ljava/lang/Object;)I" + ),] + ), + java_class!( + "java.lang.Error", + vec![ + constructor!("(Ljava/lang/String;)V"), + method!("getMessage"), + field!("detailMessage"), + ] + ), + java_class!("java.math.BigInteger", vec![method!("probablePrime"),]), ]) .generate(&generated_dir) .unwrap_or_else(|e| { diff --git a/jni-gen/systest/src/lib.rs b/jni-gen/systest/src/lib.rs index 128c493d5f0..89f78d0f4df 100644 --- a/jni-gen/systest/src/lib.rs +++ b/jni-gen/systest/src/lib.rs @@ -1,18 +1,14 @@ +#[rustfmt::skip] #[path = "../gen/mod.rs"] pub mod wrappers; -use jni::JNIEnv; -use jni::JavaVM; -use jni::InitArgsBuilder; -use jni::JNIVersion; -use jni::errors::Result; +use jni::{errors::Result, InitArgsBuilder, JNIEnv, JNIVersion, JavaVM}; use std::sync::Once; pub fn print_exception(env: &JNIEnv) { let exception_occurred = env.exception_check().unwrap_or_else(|e| panic!("{e:?}")); if exception_occurred { - env.exception_describe() - .unwrap_or_else(|e| panic!("{e:?}")); + env.exception_describe().unwrap_or_else(|e| panic!("{e:?}")); } } @@ -25,19 +21,19 @@ static mut JVM: Option = None; fn init_jvm() -> Result<()> { INIT_JVM.call_once(|| { let jvm_args = InitArgsBuilder::new() - .version(JNIVersion::V8) - .option("-Xcheck:jni") - .option("-Xdebug") - .option("-XX:+CheckJNICalls") - .build() - .unwrap_or_else(|e| { - panic!("{} source: {:?}", e, std::error::Error::source(&e)); - }); + .version(JNIVersion::V8) + .option("-Xcheck:jni") + .option("-Xdebug") + .option("-XX:+CheckJNICalls") + .build() + .unwrap_or_else(|e| { + panic!("{} source: {:?}", e, std::error::Error::source(&e)); + }); let jvm = JavaVM::new(jvm_args).unwrap_or_else(|e| { panic!("{} source: {:?}", e, std::error::Error::source(&e)); }); - + unsafe { JVM = Some(jvm); } @@ -54,4 +50,4 @@ pub fn get_jvm() -> Result<&'static JavaVM> { panic!("Failed to get JVM reference") } } -} \ No newline at end of file +} diff --git a/jni-gen/systest/tests/constructor_check_fails.rs b/jni-gen/systest/tests/constructor_check_fails.rs index 34b67b9725b..1b978105be1 100644 --- a/jni-gen/systest/tests/constructor_check_fails.rs +++ b/jni-gen/systest/tests/constructor_check_fails.rs @@ -1,11 +1,11 @@ use jni::objects::JObject; -use systest::get_jvm; -use systest::print_exception; -use systest::wrappers::*; +use systest::{get_jvm, print_exception, wrappers::*}; #[test] #[cfg(debug_assertions)] -#[should_panic(expected = "Java binding type failure. Expected object of class java/lang/String, but got java/lang/Integer instead")] +#[should_panic( + expected = "Java binding type failure. Expected object of class java/lang/String, but got java/lang/Integer instead" +)] fn constructor_should_fail_on_wrong_argument() { let jvm = get_jvm().expect("failed go get jvm reference"); @@ -18,7 +18,8 @@ fn constructor_should_fail_on_wrong_argument() { let error_wrapper = java::lang::Error::with(&env); let _result = error_wrapper.new(integer_object); Ok(JObject::null()) - }).unwrap_or_else(|e| { + }) + .unwrap_or_else(|e| { print_exception(&env); panic!("{} source: {:?}", e, std::error::Error::source(&e)); }); diff --git a/jni-gen/systest/tests/field_getter_check_fails.rs b/jni-gen/systest/tests/field_getter_check_fails.rs index 99b12d86893..336ab8a1751 100644 --- a/jni-gen/systest/tests/field_getter_check_fails.rs +++ b/jni-gen/systest/tests/field_getter_check_fails.rs @@ -1,11 +1,11 @@ use jni::objects::JObject; -use systest::get_jvm; -use systest::print_exception; -use systest::wrappers::*; +use systest::{get_jvm, print_exception, wrappers::*}; #[test] #[cfg(debug_assertions)] -#[should_panic(expected = "Java binding type failure. Expected object of class java/lang/Error, but got java/lang/Integer instead")] +#[should_panic( + expected = "Java binding type failure. Expected object of class java/lang/Error, but got java/lang/Integer instead" +)] fn field_getter_should_fail_on_wrong_receiver() { let jvm = get_jvm().expect("failed go get jvm reference"); @@ -18,7 +18,8 @@ fn field_getter_should_fail_on_wrong_receiver() { let integer_object = java::lang::Integer::with(&env).new(1337)?; let _result = error_wrapper.get_detailMessage(integer_object); Ok(JObject::null()) - }).unwrap_or_else(|e| { + }) + .unwrap_or_else(|e| { print_exception(&env); panic!("{} source: {:?}", e, std::error::Error::source(&e)); }); diff --git a/jni-gen/systest/tests/field_setter_check_fails.rs b/jni-gen/systest/tests/field_setter_check_fails.rs index 3c3d814aafe..b4716d7b39b 100644 --- a/jni-gen/systest/tests/field_setter_check_fails.rs +++ b/jni-gen/systest/tests/field_setter_check_fails.rs @@ -1,10 +1,5 @@ -use jni::objects::JObject; -use jni::JNIEnv; -use jni::errors::Result as JNIResult; -use systest::get_jvm; -use systest::print_exception; -use systest::wrappers::*; - +use jni::{errors::Result as JNIResult, objects::JObject, JNIEnv}; +use systest::{get_jvm, print_exception, wrappers::*}; fn string_to_jobject<'a>(env: &JNIEnv<'a>, string: &str) -> JNIResult> { Ok(JObject::from(env.new_string(string.to_owned())?)) @@ -12,7 +7,9 @@ fn string_to_jobject<'a>(env: &JNIEnv<'a>, string: &str) -> JNIResult(env: &JNIEnv<'a>, string: &str) -> JNIResult> { Ok(JObject::from(env.new_string(string.to_owned())?)) @@ -27,15 +26,12 @@ fn test_jvm_builtin_classes() { env.with_local_frame(16, || { let integer_value = java::lang::Integer::with(&env).new(int_value)?; - let int_array = env.new_object_array( - array_length, - "java/lang/Integer", - integer_value, - )?; + let int_array = + env.new_object_array(array_length, "java/lang/Integer", integer_value)?; let int_array = unsafe { JObject::from_raw(int_array) }; - let result = java::util::Arrays::with(&env) - .call_binarySearch(int_array, integer_value)?; + let result = + java::util::Arrays::with(&env).call_binarySearch(int_array, integer_value)?; assert!(0 <= result && result < array_length); @@ -57,7 +53,8 @@ fn test_jvm_builtin_classes() { assert!(java::lang::Integer::with(&env).get_value(integer_value)? == new_wal); Ok(JObject::null()) - }).unwrap_or_else(|e| { + }) + .unwrap_or_else(|e| { print_exception(&env); panic!("{} source: {:?}", e, std::error::Error::source(&e)); }); @@ -65,23 +62,28 @@ fn test_jvm_builtin_classes() { env.with_local_frame(16, || { let error_wrapper = java::lang::Error::with(&env); - + // Initalize error and check its content let innitial_message = "First error message".to_string(); let error = error_wrapper.new(string_to_jobject(&env, &innitial_message)?)?; - assert!(jobject_to_string(&env, error_wrapper.get_detailMessage(error)?)? == innitial_message); + assert!( + jobject_to_string(&env, error_wrapper.get_detailMessage(error)?)? == innitial_message + ); // Update the error object and check that the content has changed accordingly let another_message = "Second message".to_string(); error_wrapper.set_detailMessage(error, string_to_jobject(&env, &another_message)?)?; - assert!(jobject_to_string(&env, error_wrapper.get_detailMessage(error)?)? == another_message); + assert!( + jobject_to_string(&env, error_wrapper.get_detailMessage(error)?)? == another_message + ); // Try calling the getMessage method to achieve the same result assert!(jobject_to_string(&env, error_wrapper.call_getMessage(error)?)? == another_message); Ok(JObject::null()) - }).unwrap_or_else(|e| { + }) + .unwrap_or_else(|e| { print_exception(&env); panic!("{} source: {:?}", e, std::error::Error::source(&e)); - }); + }); } diff --git a/jni-gen/systest/tests/method_runtime_check_fails.rs b/jni-gen/systest/tests/method_runtime_check_fails.rs index bd744f00388..bf14231843a 100644 --- a/jni-gen/systest/tests/method_runtime_check_fails.rs +++ b/jni-gen/systest/tests/method_runtime_check_fails.rs @@ -1,9 +1,5 @@ -use jni::objects::JObject; -use jni::JNIEnv; -use jni::errors::Result as JNIResult; -use systest::get_jvm; -use systest::print_exception; -use systest::wrappers::*; +use jni::{errors::Result as JNIResult, objects::JObject, JNIEnv}; +use systest::{get_jvm, print_exception, wrappers::*}; fn string_to_jobject<'a>(env: &JNIEnv<'a>, string: &str) -> JNIResult> { Ok(JObject::from(env.new_string(string.to_owned())?)) @@ -11,7 +7,9 @@ fn string_to_jobject<'a>(env: &JNIEnv<'a>, string: &str) -> JNIResult(env: &JNIEnv<'a>, string: &str) -> JNIResult> { Ok(JObject::from(env.new_string(string.to_owned())?)) @@ -11,7 +7,9 @@ fn string_to_jobject<'a>(env: &JNIEnv<'a>, string: &str) -> JNIResult { impl<'p, 'v: 'p, 'tcx: 'v> BuiltinEncoder<'p, 'v, 'tcx> { pub fn new(encoder: &'p super::Encoder<'v, 'tcx>) -> Self { - Self { - encoder - } + Self { encoder } } pub fn encode_builtin_method_name(&self, method: BuiltinMethodKind) -> String { match method { BuiltinMethodKind::HavocBool => "builtin$havoc_bool".to_string(), BuiltinMethodKind::HavocInt => "builtin$havoc_int".to_string(), - BuiltinMethodKind::HavocBV(variant) => format!("builtin$havoc_{variant}"), + BuiltinMethodKind::HavocBV(variant) => format!("builtin$havoc_{variant}"), BuiltinMethodKind::HavocF32 => "builtin$havoc_f32".to_string(), BuiltinMethodKind::HavocF64 => "builtin$havoc_f64".to_string(), BuiltinMethodKind::HavocRef => "builtin$havoc_ref".to_string(), @@ -80,7 +81,10 @@ impl<'p, 'v: 'p, 'tcx: 'v> BuiltinEncoder<'p, 'v, 'tcx> { } } - pub fn encode_builtin_method_def(&self, method: BuiltinMethodKind) -> EncodingResult { + pub fn encode_builtin_method_def( + &self, + method: BuiltinMethodKind, + ) -> EncodingResult { let method_name = self.encode_builtin_method_name(method); let return_type = match method { BuiltinMethodKind::HavocBool => vir::Type::Bool, @@ -96,14 +100,16 @@ impl<'p, 'v: 'p, 'tcx: 'v> BuiltinEncoder<'p, 'v, 'tcx> { Ok(vir::BodylessMethod { name: method_name, formal_args: vec![], - formal_returns: vec![vir_local!{ ret: {return_type} }], + formal_returns: vec![vir_local! { ret: {return_type} }], pres: vec![], posts: vec![], }) } pub fn encode_builtin_function_def(&self, function: BuiltinFunctionKind) -> vir::Function { - let (fn_name, type_arguments) = self.encoder.encode_builtin_function_name_with_type_args(&function); + let (fn_name, type_arguments) = self + .encoder + .encode_builtin_function_name_with_type_args(&function); match function { BuiltinFunctionKind::Unreachable(typ) => vir::Function { name: fn_name, @@ -124,9 +130,14 @@ impl<'p, 'v: 'p, 'tcx: 'v> BuiltinEncoder<'p, 'v, 'tcx> { posts: vec![], body: None, }, - BuiltinFunctionKind::ArrayLookupPure { array_pred_type, array_len, return_ty, .. } => { + BuiltinFunctionKind::ArrayLookupPure { + array_pred_type, + array_len, + return_ty, + .. + } => { let self_var = vir::LocalVar::new("self", array_pred_type.clone()); - let idx_var = vir_local!{ idx: Int }; + let idx_var = vir_local! { idx: Int }; vir::Function { name: fn_name, @@ -146,29 +157,32 @@ impl<'p, 'v: 'p, 'tcx: 'v> BuiltinEncoder<'p, 'v, 'tcx> { vir::PermAmount::Read, ), // 0 <= idx < {len} - vir_expr!{ [vir::Expr::from(0u32)] <= [vir::Expr::local(idx_var.clone())] }, - vir_expr!([vir::Expr::local(idx_var)] < [vir::Expr::from(array_len)]), + vir_expr! { [vir::Expr::from(0u32)] <= [vir::Expr::local(idx_var.clone())] }, + vir_expr!([vir::Expr::local(idx_var)] < [vir::Expr::from(array_len)]), ], posts: vec![], body: None, } - }, - BuiltinFunctionKind::SliceLookupPure { slice_pred_type, elem_pred_type, return_ty} => { - let (slice_len, slice_len_type_arguments) = self.encoder.encode_builtin_function_name_with_type_args( - &BuiltinFunctionKind::SliceLen { slice_pred_type: slice_pred_type.clone(), elem_pred_type } - ); + } + BuiltinFunctionKind::SliceLookupPure { + slice_pred_type, + elem_pred_type, + return_ty, + } => { + let (slice_len, slice_len_type_arguments) = self + .encoder + .encode_builtin_function_name_with_type_args(&BuiltinFunctionKind::SliceLen { + slice_pred_type: slice_pred_type.clone(), + elem_pred_type, + }); let self_var = vir::LocalVar::new("self", slice_pred_type.clone()); - let idx_var = vir_local!{ idx: Int }; + let idx_var = vir_local! { idx: Int }; let slice_len_call = vir::Expr::func_app( slice_len, slice_len_type_arguments, - vec![ - vir::Expr::local(self_var.clone()), - ], - vec![ - self_var.clone(), - ], + vec![vir::Expr::local(self_var.clone())], + vec![self_var.clone()], vir::Type::Int, vir::Position::default(), ); @@ -176,10 +190,7 @@ impl<'p, 'v: 'p, 'tcx: 'v> BuiltinEncoder<'p, 'v, 'tcx> { vir::Function { name: fn_name, type_arguments, - formal_args: vec![ - self_var.clone(), - idx_var.clone(), - ], + formal_args: vec![self_var.clone(), idx_var.clone()], return_type: return_ty, pres: vec![ // acc(self, read$()) @@ -189,38 +200,36 @@ impl<'p, 'v: 'p, 'tcx: 'v> BuiltinEncoder<'p, 'v, 'tcx> { vir::PermAmount::Read, ), // 0 <= idx < Slice${ty}$len(self) - vir_expr!{ [vir::Expr::from(0u32)] <= [vir::Expr::local(idx_var.clone())] }, - vir_expr!{ [vir::Expr::local(idx_var)] < [slice_len_call] }, + vir_expr! { [vir::Expr::from(0u32)] <= [vir::Expr::local(idx_var.clone())] }, + vir_expr! { [vir::Expr::local(idx_var)] < [slice_len_call] }, ], posts: vec![], body: None, } - }, - BuiltinFunctionKind::SliceLen { slice_pred_type, .. } => { + } + BuiltinFunctionKind::SliceLen { + slice_pred_type, .. + } => { let self_var = vir::LocalVar::new("self", slice_pred_type.clone()); vir::Function { name: fn_name, type_arguments, - formal_args: vec![ - self_var.clone(), - ], + formal_args: vec![self_var.clone()], return_type: vir::Type::Int, - pres: vec![ - vir::Expr::predicate_access_predicate( - slice_pred_type, - vir::Expr::local(self_var), - vir::PermAmount::Read, - ), - ], + pres: vec![vir::Expr::predicate_access_predicate( + slice_pred_type, + vir::Expr::local(self_var), + vir::PermAmount::Read, + )], posts: vec![ - vir_expr!{ [vir::Expr::from(vir_local!{ __result: Int })] >= [vir::Expr::from(0)] }, + vir_expr! { [vir::Expr::from(vir_local!{ __result: Int })] >= [vir::Expr::from(0)] }, // TODO: We should use a symbolic value for usize::MAX. - vir_expr!{ [vir::Expr::from(vir_local!{ __result: Int })] <= [vir::Expr::from(usize::MAX)] }, + vir_expr! { [vir::Expr::from(vir_local!{ __result: Int })] <= [vir::Expr::from(usize::MAX)] }, ], body: None, } - }, + } } } @@ -302,13 +311,14 @@ impl<'p, 'v: 'p, 'tcx: 'v> BuiltinEncoder<'p, 'v, 'tcx> { }; functions.push(f.clone()); - let forall_arg = vir_local!{ self: {t.clone()} }; + let forall_arg = vir_local! { self: {t.clone()} }; let function_app = vir::Expr::domain_func_app(f.clone(), vec![vir::Expr::local(forall_arg.clone())]); let body = vir::Expr::forall( vec![forall_arg], vec![vir::Trigger::new(vec![function_app.clone()])], - function_app); + function_app, + ); let axiom = vir::DomainAxiom { comment: None, name: format!("{}$axiom", f.get_identifier()), diff --git a/prusti-viper/src/encoder/encoder.rs b/prusti-viper/src/encoder/encoder.rs index a60f83ca119..5a1407f86c7 100644 --- a/prusti-viper/src/encoder/encoder.rs +++ b/prusti-viper/src/encoder/encoder.rs @@ -4,66 +4,68 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -use ::log::{info, debug}; -use prusti_common::utils::identifiers::encode_identifier; -use vir_crate::common::check_mode::CheckMode; -use crate::encoder::builtin_encoder::BuiltinEncoder; -use crate::encoder::builtin_encoder::BuiltinMethodKind; -use crate::encoder::errors::{ErrorManager, SpannedEncodingError, EncodingError}; -use crate::encoder::foldunfold; -use crate::encoder::procedure_encoder::ProcedureEncoder; -use crate::error_unsupported; -use prusti_common::{vir_expr, vir_local}; -use prusti_common::config; -use prusti_common::report::log; -use prusti_interface::data::ProcedureDefId; -use prusti_interface::environment::Environment; -use prusti_interface::specs::typed; -use prusti_interface::PrustiError; -use vir_crate::polymorphic::{self as vir}; -use vir_crate::common::identifier::WithIdentifier; -use prusti_rustc_interface::hir::def_id::DefId; -use prusti_rustc_interface::middle::mir; -use prusti_rustc_interface::middle::ty; -use std::cell::{Cell, RefCell, RefMut, Ref}; -use std::fmt::Debug; -use rustc_hash::{FxHashSet, FxHashMap}; -use std::io::Write; -use std::rc::Rc; -use crate::encoder::stub_procedure_encoder::StubProcedureEncoder; -use std::ops::AddAssign; -use prusti_interface::specs::typed::ProcedureSpecificationKind; -use crate::encoder::name_interner::NameInterner; -use crate::encoder::errors::EncodingResult; -use crate::encoder::errors::SpannedEncodingResult; -use crate::encoder::mirror_function_encoder::MirrorEncoder; -use crate::encoder::snapshot::interface::{SnapshotEncoderInterface, SnapshotEncoderState}; -use crate::encoder::purifier; -use super::builtin_encoder::BuiltinDomainKind; -use super::high::builtin_functions::HighBuiltinFunctionEncoderState; -use super::middle::core_proof::{MidCoreProofEncoderState, MidCoreProofEncoderInterface}; -use super::mir::{ - sequences::{ - MirSequencesEncoderState, MirSequencesEncoderInterface, +use super::{ + builtin_encoder::BuiltinDomainKind, + counterexamples::{DiscriminantsState, MirProcedureMapping, MirProcedureMappingInterface}, + high::{ + builtin_functions::HighBuiltinFunctionEncoderState, + to_typed::types::HighToTypedTypeEncoderState, + types::{HighTypeEncoderInterface, HighTypeEncoderState}, }, - contracts::ContractsEncoderState, - procedures::MirProcedureEncoderState, - type_invariants::TypeInvariantEncoderState, - pure::{ - PureFunctionEncoderState, PureFunctionEncoderInterface, + middle::core_proof::{MidCoreProofEncoderInterface, MidCoreProofEncoderState}, + mir::{ + contracts::ContractsEncoderState, + procedures::MirProcedureEncoderState, + pure::{PureFunctionEncoderInterface, PureFunctionEncoderState}, + sequences::{MirSequencesEncoderInterface, MirSequencesEncoderState}, + specifications::{SpecificationsInterface, SpecificationsState}, + type_invariants::TypeInvariantEncoderState, + types::{compute_discriminant_bounds, MirTypeEncoderInterface, MirTypeEncoderState}, }, - types::{ - compute_discriminant_bounds, - MirTypeEncoderState, MirTypeEncoderInterface, +}; +use crate::{ + encoder::{ + builtin_encoder::{BuiltinEncoder, BuiltinMethodKind}, + errors::{ + EncodingError, EncodingResult, ErrorManager, SpannedEncodingError, + SpannedEncodingResult, + }, + foldunfold, + mirror_function_encoder::MirrorEncoder, + name_interner::NameInterner, + procedure_encoder::ProcedureEncoder, + purifier, + snapshot::interface::{SnapshotEncoderInterface, SnapshotEncoderState}, + stub_procedure_encoder::StubProcedureEncoder, }, - specifications::{ - SpecificationsState, SpecificationsInterface, - } + error_unsupported, +}; +use ::log::{debug, info}; +use prusti_common::{ + config, report::log, utils::identifiers::encode_identifier, vir_expr, vir_local, +}; +use prusti_interface::{ + data::ProcedureDefId, + environment::Environment, + specs::{typed, typed::ProcedureSpecificationKind}, + PrustiError, +}; +use prusti_rustc_interface::{ + hir::def_id::DefId, + middle::{mir, ty}, +}; +use rustc_hash::{FxHashMap, FxHashSet}; +use std::{ + cell::{Cell, Ref, RefCell, RefMut}, + fmt::Debug, + io::Write, + ops::AddAssign, + rc::Rc, +}; +use vir_crate::{ + common::{check_mode::CheckMode, identifier::WithIdentifier}, + polymorphic::{self as vir}, }; -use super::high::types::{HighTypeEncoderState, HighTypeEncoderInterface}; -use super::counterexamples::{MirProcedureMappingInterface, MirProcedureMapping}; -use super::counterexamples::DiscriminantsState; -use super::high::to_typed::types::HighToTypedTypeEncoderState; pub struct Encoder<'v, 'tcx: 'v> { env: &'v Environment<'tcx>, @@ -118,36 +120,31 @@ pub enum EncodingTask<'tcx> { // If the field name is an identifier, removing the leading prefix r# pub fn encode_field_name(field_name: &str) -> String { - format!("f${}", field_name.trim_start_matches("r#")) + format!("f${}", field_name.trim_start_matches("r#")) } impl<'v, 'tcx> Encoder<'v, 'tcx> { - pub fn new( - env: &'v Environment<'tcx>, - def_spec: typed::DefSpecificationMap, - ) -> Self { + pub fn new(env: &'v Environment<'tcx>, def_spec: typed::DefSpecificationMap) -> Self { let source_path = env.name.source_path(); let source_filename = source_path.file_name().unwrap().to_str().unwrap(); - let vir_program_before_foldunfold_writer = config::dump_debug_info().then_some(()).map(|_| - RefCell::new( - log::build_writer( - "vir_program_before_foldunfold", - format!("{source_filename}.vir"), + let vir_program_before_foldunfold_writer = + config::dump_debug_info().then_some(()).map(|_| { + RefCell::new( + log::build_writer( + "vir_program_before_foldunfold", + format!("{source_filename}.vir"), + ) + .ok() + .unwrap(), ) - .ok() - .unwrap(), - ) - ); - let vir_program_before_viper_writer = config::dump_debug_info().then_some(()).map(|_| + }); + let vir_program_before_viper_writer = config::dump_debug_info().then_some(()).map(|_| { RefCell::new( - log::build_writer( - "vir_program_before_viper", - format!("{source_filename}.vir"), - ) + log::build_writer("vir_program_before_viper", format!("{source_filename}.vir")) .ok() .unwrap(), ) - ); + }); Encoder { env, @@ -232,9 +229,18 @@ impl<'v, 'tcx> Encoder<'v, 'tcx> { self.error_manager.borrow_mut() } - pub fn finalize_viper_program(&self, name: String, proc_def_id: DefId) -> SpannedEncodingResult { + pub fn finalize_viper_program( + &self, + name: String, + proc_def_id: DefId, + ) -> SpannedEncodingResult { let error_span = self.env.query.get_def_span(proc_def_id); - super::definition_collector::collect_definitions(error_span, self, name, self.get_used_viper_methods()) + super::definition_collector::collect_definitions( + error_span, + self, + name, + self.get_used_viper_methods(), + ) } pub fn get_viper_programs(&mut self) -> Vec { @@ -242,14 +248,19 @@ impl<'v, 'tcx> Encoder<'v, 'tcx> { } pub fn get_core_proof_programs(&mut self) -> Vec { - if config::counterexample() && config::unsafe_core_proof(){ - self.take_core_proof_programs().into_iter().map( - | program | { + if config::counterexample() && config::unsafe_core_proof() { + self.take_core_proof_programs() + .into_iter() + .map(|program| { self.add_mapping(&program); prusti_common::vir::program::Program::Low(program) - }).collect() + }) + .collect() } else { - self.take_core_proof_programs().into_iter().map(prusti_common::vir::program::Program::Low).collect() + self.take_core_proof_programs() + .into_iter() + .map(prusti_common::vir::program::Program::Low) + .collect() } } @@ -276,11 +287,20 @@ impl<'v, 'tcx> Encoder<'v, 'tcx> { pub(super) fn insert_function(&self, function: vir::Function) -> vir::FunctionIdentifier { let identifier: vir::FunctionIdentifier = function.get_identifier().into(); - assert!(self.functions.borrow_mut().insert(identifier.clone(), Rc::new(function)).is_none(), "{identifier:?} is not unique"); + assert!( + self.functions + .borrow_mut() + .insert(identifier.clone(), Rc::new(function)) + .is_none(), + "{identifier:?} is not unique" + ); identifier } - pub(super) fn get_function(&self, identifier: &vir::FunctionIdentifier) -> SpannedEncodingResult> { + pub(super) fn get_function( + &self, + identifier: &vir::FunctionIdentifier, + ) -> SpannedEncodingResult> { self.ensure_pure_function_encoded(identifier)?; if self.functions.borrow().contains_key(identifier) { let map = self.functions.borrow(); @@ -293,13 +313,17 @@ impl<'v, 'tcx> Encoder<'v, 'tcx> { } pub(super) fn get_builtin_methods( - &self + &self, ) -> Ref<'_, FxHashMap> { self.builtin_methods.borrow() } fn get_used_viper_methods(&self) -> Vec { - self.procedures.borrow_mut().drain().map(|(_, value)| value).collect() + self.procedures + .borrow_mut() + .drain() + .map(|(_, value)| value) + .collect() } /// Invoke const evaluation to extract scalar value. @@ -321,25 +345,29 @@ impl<'v, 'tcx> Encoder<'v, 'tcx> { ) -> EncodingResult { let opt_scalar_value = match value { mir::ConstantKind::Ty(value) => match value.kind() { - ty::ConstKind::Value(ref const_value) => { - const_value.try_to_scalar() - } + ty::ConstKind::Value(ref const_value) => const_value.try_to_scalar(), ty::ConstKind::Unevaluated(ct) => { let mir_ct = mir::UnevaluatedConst::new(ct.def, ct.args); self.uneval_eval_intlike(mir_ct) - }, + } _ => error_unsupported!("unsupported const kind: {:?}", value), - } + }, mir::ConstantKind::Val(val, _) => val.try_to_scalar(), mir::ConstantKind::Unevaluated(ct, _) => self.uneval_eval_intlike(ct), }; - opt_scalar_value.ok_or_else(|| EncodingError::unsupported(format!("unsupported constant value: {value:?}"))) + opt_scalar_value.ok_or_else(|| { + EncodingError::unsupported(format!("unsupported constant value: {value:?}")) + }) } /// Encodes a value in a field if the base expression is a reference or /// a primitive types. /// For composed data structures, the base expression is returned. - pub fn encode_value_expr(&self, base: vir::Expr, ty: ty::Ty<'tcx>) -> EncodingResult { + pub fn encode_value_expr( + &self, + base: vir::Expr, + ty: ty::Ty<'tcx>, + ) -> EncodingResult { match ty.kind() { ty::TyKind::Adt(_, _) | ty::TyKind::Closure(_, _) @@ -356,15 +384,15 @@ impl<'v, 'tcx> Encoder<'v, 'tcx> { } } - pub fn encode_dereference_field(&self, ty: ty::Ty<'tcx>) - -> EncodingResult - { + pub fn encode_dereference_field(&self, ty: ty::Ty<'tcx>) -> EncodingResult { self.encode_raw_ref_field("val_ref".to_string(), ty) } - pub fn encode_struct_field(&self, field_name: &str, ty: ty::Ty<'tcx>) - -> EncodingResult - { + pub fn encode_struct_field( + &self, + field_name: &str, + ty: ty::Ty<'tcx>, + ) -> EncodingResult { self.encode_raw_ref_field(encode_field_name(field_name), ty) } @@ -376,16 +404,16 @@ impl<'v, 'tcx> Encoder<'v, 'tcx> { let typ = place.get_type().clone(); let mut name = typ.name(); name.push_str("$$discriminant$$"); - let self_local_var = vir_local!{ self: {typ.clone()} }; + let self_local_var = vir_local! { self: {typ.clone()} }; if !self.type_discriminant_funcs.borrow().contains_key(&name) { let precondition = vir::Expr::predicate_access_predicate( typ, self_local_var.clone().into(), - vir::PermAmount::Read + vir::PermAmount::Read, ); - let result = vir_local!{ __result: Int }; - let postcondition = compute_discriminant_bounds( - adt_def, self.env.tcx(), &result.clone().into()); + let result = vir_local! { __result: Int }; + let postcondition = + compute_discriminant_bounds(adt_def, self.env.tcx(), &result.clone().into()); let discr_field = self.encode_discriminant_field(); let self_local_var_expr: vir::Expr = self_local_var.clone().into(); @@ -400,7 +428,8 @@ impl<'v, 'tcx> Encoder<'v, 'tcx> { self.encode_discriminant_postcondition( self_local_var_expr.clone(), vir::Expr::local(result), - ).unwrap(), // TODO: no unwrap + ) + .unwrap(), // TODO: no unwrap ], body: Some(self_local_var_expr.field(discr_field)), }; @@ -412,9 +441,11 @@ impl<'v, 'tcx> Encoder<'v, 'tcx> { self.get_used_viper_predicates_map()?, ); let identifier = self.insert_function(final_function.unwrap()); - self.type_discriminant_funcs.borrow_mut().insert(name.clone(), identifier); + self.type_discriminant_funcs + .borrow_mut() + .insert(name.clone(), identifier); } - Ok(vir::Expr::FuncApp( vir::FuncApp { + Ok(vir::Expr::FuncApp(vir::FuncApp { function_name: name, type_arguments: Vec::new(), arguments: vec![place], @@ -425,7 +456,10 @@ impl<'v, 'tcx> Encoder<'v, 'tcx> { } #[tracing::instrument(level = "trace", skip(self))] - pub fn encode_builtin_domain(&self, domain_kind: BuiltinDomainKind) -> EncodingResult { + pub fn encode_builtin_domain( + &self, + domain_kind: BuiltinDomainKind, + ) -> EncodingResult { if !self.builtin_domains.borrow().contains_key(&domain_kind) { let builtin_encoder = BuiltinEncoder::new(self); let domain = builtin_encoder.encode_builtin_domain(domain_kind)?; @@ -437,7 +471,10 @@ impl<'v, 'tcx> Encoder<'v, 'tcx> { } #[tracing::instrument(level = "trace", skip(self))] - pub fn encode_builtin_domain_type(&self, domain_kind: BuiltinDomainKind) -> EncodingResult { + pub fn encode_builtin_domain_type( + &self, + domain_kind: BuiltinDomainKind, + ) -> EncodingResult { // Also encode the definition, if it's not already under construction. let mut domains_in_progress = self.builtin_domains_in_progress.borrow_mut(); if !domains_in_progress.contains(&domain_kind) { @@ -452,7 +489,10 @@ impl<'v, 'tcx> Encoder<'v, 'tcx> { } #[tracing::instrument(level = "trace", skip(self))] - pub fn encode_builtin_method_def(&self, method_kind: BuiltinMethodKind) -> EncodingResult { + pub fn encode_builtin_method_def( + &self, + method_kind: BuiltinMethodKind, + ) -> EncodingResult { if !self.builtin_methods.borrow().contains_key(&method_kind) { let builtin_encoder = BuiltinEncoder::new(self); let method = builtin_encoder.encode_builtin_method_def(method_kind)?; @@ -465,7 +505,10 @@ impl<'v, 'tcx> Encoder<'v, 'tcx> { } #[tracing::instrument(level = "trace", skip(self))] - pub fn encode_builtin_method_use(&self, method_kind: BuiltinMethodKind) -> EncodingResult { + pub fn encode_builtin_method_use( + &self, + method_kind: BuiltinMethodKind, + ) -> EncodingResult { // Trigger encoding of definition self.encode_builtin_method_def(method_kind)?; let builtin_encoder = BuiltinEncoder::new(self); @@ -473,13 +516,19 @@ impl<'v, 'tcx> Encoder<'v, 'tcx> { } #[tracing::instrument(level = "trace", skip(self))] - pub fn encode_cast_function_use(&self, src_ty: ty::Ty<'tcx>, dst_ty: ty::Ty<'tcx>) - -> EncodingResult - { + pub fn encode_cast_function_use( + &self, + src_ty: ty::Ty<'tcx>, + dst_ty: ty::Ty<'tcx>, + ) -> EncodingResult { let function_name = format!("builtin$cast${src_ty}${dst_ty}"); - if !self.type_cast_functions.borrow().contains_key(&(src_ty, dst_ty)) { - let arg = vir_local!{ number: {self.encode_snapshot_type(src_ty)?} }; - let result = vir_local!{ __result: {self.encode_snapshot_type(dst_ty)?} }; + if !self + .type_cast_functions + .borrow() + .contains_key(&(src_ty, dst_ty)) + { + let arg = vir_local! { number: {self.encode_snapshot_type(src_ty)?} }; + let result = vir_local! { __result: {self.encode_snapshot_type(dst_ty)?} }; let mut precondition = self.encode_type_bounds(&arg.clone().into(), src_ty); precondition.extend(self.encode_type_bounds(&arg.clone().into(), dst_ty)); let postcondition = self.encode_type_bounds(&result.into(), dst_ty); @@ -493,18 +542,28 @@ impl<'v, 'tcx> Encoder<'v, 'tcx> { body: Some(arg.into()), }; let identifier = self.insert_function(function); - self.type_cast_functions.borrow_mut().insert((src_ty, dst_ty), identifier); + self.type_cast_functions + .borrow_mut() + .insert((src_ty, dst_ty), identifier); } Ok(function_name) } #[tracing::instrument(level = "trace", skip(self))] - pub fn encode_unsize_function_use(&self, src_ty: ty::Ty<'tcx>, dst_ty: ty::Ty<'tcx>) - -> EncodingResult - { + pub fn encode_unsize_function_use( + &self, + src_ty: ty::Ty<'tcx>, + dst_ty: ty::Ty<'tcx>, + ) -> EncodingResult { // at some point we may want to add support for other types of unsizing calls? - assert!(matches!(src_ty.kind(), ty::TyKind::Array(..) | ty::TyKind::Slice(..))); - assert!(matches!(dst_ty.kind(), ty::TyKind::Array(..) | ty::TyKind::Slice(..))); + assert!(matches!( + src_ty.kind(), + ty::TyKind::Array(..) | ty::TyKind::Slice(..) + )); + assert!(matches!( + dst_ty.kind(), + ty::TyKind::Array(..) | ty::TyKind::Slice(..) + )); let array_types = self.encode_sequence_types(src_ty)?; let slice_types = self.encode_sequence_types(dst_ty)?; @@ -514,10 +573,14 @@ impl<'v, 'tcx> Encoder<'v, 'tcx> { &slice_types.sequence_pred_type.name() ); - if !self.type_cast_functions.borrow().contains_key(&(src_ty, dst_ty)) { + if !self + .type_cast_functions + .borrow() + .contains_key(&(src_ty, dst_ty)) + { let src_snap_ty = self.encode_snapshot_type(src_ty)?; let dst_snap_ty = self.encode_snapshot_type(dst_ty)?; - let arg = vir_local!{ array: {src_snap_ty} }; + let arg = vir_local! { array: {src_snap_ty} }; let arg_expr = vir::Expr::from(arg.clone()); let array_uncons = self.encode_snapshot_destructor(src_ty, vec![arg_expr.clone()])?; let slice_cons = self.encode_snapshot(dst_ty, None, vec![array_uncons.clone()])?; @@ -527,10 +590,10 @@ impl<'v, 'tcx> Encoder<'v, 'tcx> { right: Box::new(true.into()), // unused position: vir::Position::default(), }); - let result = vir::Expr::from(vir_local!{ __result: {dst_snap_ty.clone()} }); + let result = vir::Expr::from(vir_local! { __result: {dst_snap_ty.clone()} }); let postcondition = vec![ - vir_expr!{ [data_len] == [array_types.len(self, arg_expr)] }, - vir_expr!{ [result] == [slice_cons]}, + vir_expr! { [data_len] == [array_types.len(self, arg_expr)] }, + vir_expr! { [result] == [slice_cons]}, ]; let function = vir::Function { name: function_name.clone(), @@ -542,7 +605,9 @@ impl<'v, 'tcx> Encoder<'v, 'tcx> { body: None, }; let identifier = self.insert_function(function); - self.type_cast_functions.borrow_mut().insert((src_ty, dst_ty), identifier); + self.type_cast_functions + .borrow_mut() + .insert((src_ty, dst_ty), identifier); } Ok(function_name) } @@ -563,7 +628,7 @@ impl<'v, 'tcx> Encoder<'v, 'tcx> { Err(error) => { self.register_encoding_error(error); StubProcedureEncoder::new(self, &procedure).encode() - }, + } }; self.log_vir_program_before_viper(method.to_string()); @@ -593,8 +658,7 @@ impl<'v, 'tcx> Encoder<'v, 'tcx> { | ty::TyKind::Array(..) | ty::TyKind::Slice(..) | ty::TyKind::Param(_) => true, // TODO(tymap): this is weird, use substs properly? - ty::TyKind::Adt(_, _) - | ty::TyKind::Closure(_, _) => { + ty::TyKind::Adt(_, _) | ty::TyKind::Closure(_, _) => { self.env.tcx().has_structural_eq_impls(ty) } _ => false, @@ -605,7 +669,7 @@ impl<'v, 'tcx> Encoder<'v, 'tcx> { pub fn encode_const_expr( &self, ty: ty::Ty<'tcx>, - value: mir::ConstantKind<'tcx> + value: mir::ConstantKind<'tcx>, ) -> EncodingResult { let scalar_value = self.const_eval_intlike(value)?; @@ -617,20 +681,26 @@ impl<'v, 'tcx> Encoder<'v, 'tcx> { ty::TyKind::Int(ty::IntTy::I32) => scalar_value.to_i32().unwrap().into(), ty::TyKind::Int(ty::IntTy::I64) => scalar_value.to_i64().unwrap().into(), ty::TyKind::Int(ty::IntTy::I128) => scalar_value.to_i128().unwrap().into(), - ty::TyKind::Int(ty::IntTy::Isize) => scalar_value.to_target_isize(&self.env.tcx()).unwrap().into(), + ty::TyKind::Int(ty::IntTy::Isize) => scalar_value + .to_target_isize(&self.env.tcx()) + .unwrap() + .into(), ty::TyKind::Uint(ty::UintTy::U8) => scalar_value.to_u8().unwrap().into(), ty::TyKind::Uint(ty::UintTy::U16) => scalar_value.to_u16().unwrap().into(), ty::TyKind::Uint(ty::UintTy::U32) => scalar_value.to_u32().unwrap().into(), ty::TyKind::Uint(ty::UintTy::U64) => scalar_value.to_u64().unwrap().into(), ty::TyKind::Uint(ty::UintTy::U128) => scalar_value.to_u128().unwrap().into(), - ty::TyKind::Uint(ty::UintTy::Usize) => scalar_value.to_target_usize(&self.env.tcx()).unwrap().into(), + ty::TyKind::Uint(ty::UintTy::Usize) => scalar_value + .to_target_usize(&self.env.tcx()) + .unwrap() + .into(), ty::TyKind::Float(ty::FloatTy::F32) => { let bits = scalar_value.to_u32().unwrap(); vir::Expr::Const(vir::ConstExpr { value: vir::Const::Float(vir::FloatConst::F32(bits)), position: vir::Position::default(), }) - }, + } ty::TyKind::Float(ty::FloatTy::F64) => { let bits = scalar_value.to_u64().unwrap(); vir::Expr::Const(vir::ConstExpr { @@ -638,12 +708,10 @@ impl<'v, 'tcx> Encoder<'v, 'tcx> { position: vir::Position::default(), }) } - ty::TyKind::FnDef(..) => { - vir::Expr::Const(vir::ConstExpr { - value: vir::Const::FnPtr, - position: vir::Position::default(), - }) - } + ty::TyKind::FnDef(..) => vir::Expr::Const(vir::ConstExpr { + value: vir::Const::FnPtr, + position: vir::Position::default(), + }), _ => { error_unsupported!("unsupported constant type {:?}", ty.kind()); } @@ -675,26 +743,37 @@ impl<'v, 'tcx> Encoder<'v, 'tcx> { /// To be used for encoding impure functions. pub fn encode_item_name(&self, def_id: DefId) -> String { - let full_name = format!("m_{}", encode_identifier(self.env.name.get_unique_item_name(def_id))); - let short_name = format!("m_{}", encode_identifier( - self.env.name.get_item_name(def_id) - )); + let full_name = format!( + "m_{}", + encode_identifier(self.env.name.get_unique_item_name(def_id)) + ); + let short_name = format!( + "m_{}", + encode_identifier(self.env.name.get_item_name(def_id)) + ); self.intern_viper_identifier(full_name, short_name) } /// To be used for encoding pure functions. pub fn encode_pure_item_name(&self, def_id: DefId) -> String { - let full_name = format!("f_{}", encode_identifier(self.env.name.get_unique_item_name(def_id))); - let short_name = format!("f_{}", encode_identifier( - self.env.name.get_item_name(def_id) - )); + let full_name = format!( + "f_{}", + encode_identifier(self.env.name.get_unique_item_name(def_id)) + ); + let short_name = format!( + "f_{}", + encode_identifier(self.env.name.get_item_name(def_id)) + ); self.intern_viper_identifier(full_name, short_name) } pub fn queue_procedure_encoding(&self, def_id: ProcedureDefId) { self.encoding_queue .borrow_mut() - .push(EncodingTask::Procedure { def_id, substs: Vec::new() }); + .push(EncodingTask::Procedure { + def_id, + substs: Vec::new(), + }); } pub fn queue_type_encoding(&self, ty: ty::Ty<'tcx>) { @@ -717,7 +796,10 @@ impl<'v, 'tcx> Encoder<'v, 'tcx> { queue.pop() } { match task { - EncodingTask::Procedure { def_id: proc_def_id, substs } => { + EncodingTask::Procedure { + def_id: proc_def_id, + substs, + } => { let proc_name = self.env.name.get_unique_item_name(proc_def_id); let proc_def_path = self.env.name.get_item_def_path(proc_def_id); info!("Encoding: {} ({})", proc_name, proc_def_path); @@ -725,26 +807,44 @@ impl<'v, 'tcx> Encoder<'v, 'tcx> { if config::unsafe_core_proof() { if self.env.query.is_unsafe_function(proc_def_id) { - if let Err(error) = self.encode_lifetimes_core_proof(proc_def_id, CheckMode::Both) { + if let Err(error) = + self.encode_lifetimes_core_proof(proc_def_id, CheckMode::Both) + { self.register_encoding_error(error); - debug!("Error encoding function: {:?} {}", proc_def_id, CheckMode::Both); + debug!( + "Error encoding function: {:?} {}", + proc_def_id, + CheckMode::Both + ); } } else { if config::verify_core_proof() { - if let Err(error) = self.encode_lifetimes_core_proof(proc_def_id, CheckMode::CoreProof) { + if let Err(error) = self + .encode_lifetimes_core_proof(proc_def_id, CheckMode::CoreProof) + { self.register_encoding_error(error); - debug!("Error encoding function: {:?} {}", proc_def_id, CheckMode::CoreProof); + debug!( + "Error encoding function: {:?} {}", + proc_def_id, + CheckMode::CoreProof + ); } } if config::verify_specifications() { - let check_mode = if config::verify_specifications_with_core_proof() { + let check_mode = if config::verify_specifications_with_core_proof() + { CheckMode::Both } else { CheckMode::Specifications }; - if let Err(error) = self.encode_lifetimes_core_proof(proc_def_id, check_mode) { + if let Err(error) = + self.encode_lifetimes_core_proof(proc_def_id, check_mode) + { self.register_encoding_error(error); - debug!("Error encoding function: {:?} {}", proc_def_id, check_mode); + debug!( + "Error encoding function: {:?} {}", + proc_def_id, check_mode + ); } } } @@ -761,7 +861,9 @@ impl<'v, 'tcx> Encoder<'v, 'tcx> { // TODO: Make sure that this encoded function does not end up in // the Viper file because that would be unsound. let identity_substs = self.env.query.identity_substs(proc_def_id); - if let Err(error) = self.encode_pure_function_def(proc_def_id, proc_def_id, identity_substs) { + if let Err(error) = + self.encode_pure_function_def(proc_def_id, proc_def_id, identity_substs) + { self.register_encoding_error(error); debug!("Error encoding function: {:?}", proc_def_id); // Skip encoding the function as a method. @@ -775,15 +877,14 @@ impl<'v, 'tcx> Encoder<'v, 'tcx> { "Trusted procedure will not be encoded or verified: {:?}", proc_def_id ); - }, + } ProcedureSpecificationKind::Predicate(_) => { debug!( "Predicates will not be encoded or verified: {:?}", proc_def_id ); - }, - ProcedureSpecificationKind::Pure | - ProcedureSpecificationKind::Impure => { + } + ProcedureSpecificationKind::Pure | ProcedureSpecificationKind::Impure => { if let Err(error) = self.encode_procedure(proc_def_id) { self.register_encoding_error(error); debug!("Error encoding function: {:?}", proc_def_id); @@ -798,11 +899,15 @@ impl<'v, 'tcx> Encoder<'v, 'tcx> { } } } - } EncodingTask::Type { ty } => { - if config::unsafe_core_proof() && config::verify_core_proof() && config::verify_types() { - if let Err(error) = self.encode_core_proof_for_type(ty, CheckMode::CoreProof) { + if config::unsafe_core_proof() + && config::verify_core_proof() + && config::verify_types() + { + if let Err(error) = + self.encode_core_proof_for_type(ty, CheckMode::CoreProof) + { self.register_encoding_error(error); debug!("Error encoding type: {:?} {}", ty, CheckMode::CoreProof); } @@ -812,11 +917,17 @@ impl<'v, 'tcx> Encoder<'v, 'tcx> { } } - pub fn intern_viper_identifier + Debug>(&self, full_name: S, short_name: S) -> String { + pub fn intern_viper_identifier + Debug>( + &self, + full_name: S, + short_name: S, + ) -> String { let result = if config::disable_name_mangling() { short_name.as_ref().to_string() } else if config::intern_names() { - self.name_interner.borrow_mut().intern(full_name, &[short_name]) + self.name_interner + .borrow_mut() + .intern(full_name, &[short_name]) } else { full_name.as_ref().to_string() }; diff --git a/prusti-viper/src/encoder/errors/conversions.rs b/prusti-viper/src/encoder/errors/conversions.rs index d79883078b4..322c59d1e3c 100644 --- a/prusti-viper/src/encoder/errors/conversions.rs +++ b/prusti-viper/src/encoder/errors/conversions.rs @@ -4,13 +4,13 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -use prusti_interface::environment::borrowck::regions::PlaceRegionsError; use crate::encoder::errors::EncodingError; +use prusti_interface::environment::borrowck::regions::PlaceRegionsError; impl From for EncodingError { fn from(err: PlaceRegionsError) -> Self { match err { - PlaceRegionsError::Unsupported(msg) => EncodingError::unsupported(msg) + PlaceRegionsError::Unsupported(msg) => EncodingError::unsupported(msg), } } } diff --git a/prusti-viper/src/encoder/errors/encoding_error.rs b/prusti-viper/src/encoder/errors/encoding_error.rs index 939328e9ecd..795ff8eb6c7 100644 --- a/prusti-viper/src/encoder/errors/encoding_error.rs +++ b/prusti-viper/src/encoder/errors/encoding_error.rs @@ -4,11 +4,10 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -use prusti_rustc_interface::errors::MultiSpan; -use log::{debug, error}; -use crate::encoder::errors::SpannedEncodingError; -use crate::encoder::errors::EncodingErrorKind; +use crate::encoder::errors::{EncodingErrorKind, SpannedEncodingError}; use backtrace::Backtrace; +use log::{debug, error}; +use prusti_rustc_interface::errors::MultiSpan; /// An error in the encoding with *optional* information regarding the source code span. #[derive(Clone, Debug)] diff --git a/prusti-viper/src/encoder/errors/error_manager.rs b/prusti-viper/src/encoder/errors/error_manager.rs index 53d5e0e6c3d..4f350f644c9 100644 --- a/prusti-viper/src/encoder/errors/error_manager.rs +++ b/prusti-viper/src/encoder/errors/error_manager.rs @@ -6,21 +6,19 @@ use std::fmt::Debug; -use vir_crate::polymorphic::Position; +use super::PositionManager; +use log::debug; +use prusti_interface::{data::ProcedureDefId, PrustiError}; +use prusti_rustc_interface::{errors::MultiSpan, span::source_map::SourceMap}; use rustc_hash::FxHashMap; -use prusti_rustc_interface::span::source_map::SourceMap; -use prusti_rustc_interface::errors::MultiSpan; use viper::VerificationError; -use prusti_interface::PrustiError; -use log::debug; -use super::PositionManager; -use prusti_interface::data::ProcedureDefId; +use vir_crate::polymorphic::Position; -const ASSERTION_TIMEOUT_HELP_MESSAGE: &str = "This could be caused by too small assertion timeout. \ +const ASSERTION_TIMEOUT_HELP_MESSAGE: &str = + "This could be caused by too small assertion timeout. \ Try increasing it by setting the configuration parameter \ ASSERT_TIMEOUT to a larger value."; - /// The cause of a panic!() #[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] pub enum PanicCause { @@ -212,7 +210,11 @@ impl<'tcx> ErrorManager<'tcx> { } /// Register a new VIR position. - pub fn register_span + Debug>(&mut self, def_id: ProcedureDefId, span: T) -> Position { + pub fn register_span + Debug>( + &mut self, + def_id: ProcedureDefId, + span: T, + ) -> Position { self.position_manager.register_span(def_id, span) } @@ -224,10 +226,15 @@ impl<'tcx> ErrorManager<'tcx> { /// Register the ErrorCtxt on an existing VIR position. #[tracing::instrument(level = "trace", skip(self))] pub fn set_error(&mut self, pos: Position, error_ctxt: ErrorCtxt) { - assert_ne!(pos, Position::default(), "Trying to register an error on a default position"); + assert_ne!( + pos, + Position::default(), + "Trying to register an error on a default position" + ); if let Some(existing_error_ctxt) = self.error_contexts.get(&pos.id()) { debug_assert_eq!( - existing_error_ctxt, &error_ctxt, + existing_error_ctxt, + &error_ctxt, "An existing error context would be overwritten.\n\ Position id: {}\n\ Existing error context: {:?}\n\ @@ -243,7 +250,11 @@ impl<'tcx> ErrorManager<'tcx> { /// Creates a new position with `error_ctxt` that is linked to `pos`. This /// method is used for setting the surrounding context position of an /// expression's position. - pub fn set_surrounding_error_context(&mut self, pos: Position, error_ctxt: ErrorCtxt) -> Position { + pub fn set_surrounding_error_context( + &mut self, + pos: Position, + error_ctxt: ErrorCtxt, + ) -> Position { let surrounding_position = self.duplicate_position(pos); self.set_error(surrounding_position, error_ctxt); self.inner_positions.insert(surrounding_position.id(), pos); @@ -252,14 +263,21 @@ impl<'tcx> ErrorManager<'tcx> { /// Register a new VIR position with the given ErrorCtxt. /// Equivalent to calling `set_error` on the output of `register_span`. - pub fn register_error + Debug>(&mut self, span: T, error_ctxt: ErrorCtxt, def_id: ProcedureDefId) -> Position { + pub fn register_error + Debug>( + &mut self, + span: T, + error_ctxt: ErrorCtxt, + def_id: ProcedureDefId, + ) -> Position { let pos = self.register_span(def_id, span); self.set_error(pos, error_ctxt); pos } pub fn get_def_id(&self, ver_error: &VerificationError) -> Option { - ver_error.offending_pos_id.as_ref() + ver_error + .offending_pos_id + .as_ref() .and_then(|id| id.parse().ok()) .and_then(|id| self.position_manager.def_id.get(&id).copied()) } @@ -267,41 +285,33 @@ impl<'tcx> ErrorManager<'tcx> { #[tracing::instrument(level = "debug", skip(self))] pub fn translate_verification_error(&self, ver_error: &VerificationError) -> PrustiError { let opt_pos_id: Option = match ver_error.offending_pos_id { - Some(ref viper_pos_id) => { - match viper_pos_id.parse() { - Ok(pos_id) => Some(pos_id), - Err(err) => { - return PrustiError::internal( - format!( - "unexpected Viper position '{viper_pos_id}': {err}" - ), - MultiSpan::new() - ); - } + Some(ref viper_pos_id) => match viper_pos_id.parse() { + Ok(pos_id) => Some(pos_id), + Err(err) => { + return PrustiError::internal( + format!("unexpected Viper position '{viper_pos_id}': {err}"), + MultiSpan::new(), + ); } - } - None => None + }, + None => None, }; let opt_reason_pos_id: Option = match ver_error.reason_pos_id { - Some(ref viper_reason_pos_id) => { - match viper_reason_pos_id.parse() { - Ok(reason_pos_id) => Some(reason_pos_id), - Err(err) => { - return PrustiError::internal( - format!( - "unexpected Viper reason position '{viper_reason_pos_id}': {err}" - ), - MultiSpan::new() - ); - } + Some(ref viper_reason_pos_id) => match viper_reason_pos_id.parse() { + Ok(reason_pos_id) => Some(reason_pos_id), + Err(err) => { + return PrustiError::internal( + format!("unexpected Viper reason position '{viper_reason_pos_id}': {err}"), + MultiSpan::new(), + ); } - } - None => None + }, + None => None, }; - let opt_error_ctxts = opt_pos_id - .and_then(|pos_id| self.error_contexts.get(&pos_id)); - let opt_error_span = opt_pos_id.and_then(|pos_id| self.position_manager.source_span.get(&pos_id)); + let opt_error_ctxts = opt_pos_id.and_then(|pos_id| self.error_contexts.get(&pos_id)); + let opt_error_span = + opt_pos_id.and_then(|pos_id| self.position_manager.source_span.get(&pos_id)); let opt_cause_span = opt_reason_pos_id.and_then(|reason_pos_id| { let res = self.position_manager.source_span.get(&reason_pos_id); if res.is_none() { @@ -317,7 +327,7 @@ impl<'tcx> ErrorManager<'tcx> { ver_error, error_span, opt_cause_span, - error_ctxt + error_ctxt, ) } else { debug!("Unregistered verification error: {:?}", ver_error); @@ -328,24 +338,22 @@ impl<'tcx> ErrorManager<'tcx> { }; match opt_pos_id { - Some(ref pos_id) => { - PrustiError::internal( - format!( - "unregistered verification error: [{}; {}] {}", - ver_error.full_id, pos_id, ver_error.message - ), - error_span - ).set_help(ASSERTION_TIMEOUT_HELP_MESSAGE) - } - None => { - PrustiError::internal( - format!( - "unregistered verification error: [{}] {}", - ver_error.full_id, ver_error.message - ), - error_span - ).set_help(ASSERTION_TIMEOUT_HELP_MESSAGE) - } + Some(ref pos_id) => PrustiError::internal( + format!( + "unregistered verification error: [{}; {}] {}", + ver_error.full_id, pos_id, ver_error.message + ), + error_span, + ) + .set_help(ASSERTION_TIMEOUT_HELP_MESSAGE), + None => PrustiError::internal( + format!( + "unregistered verification error: [{}] {}", + ver_error.full_id, ver_error.message + ), + error_span, + ) + .set_help(ASSERTION_TIMEOUT_HELP_MESSAGE), } } } diff --git a/prusti-viper/src/encoder/errors/mod.rs b/prusti-viper/src/encoder/errors/mod.rs index feb044fa644..5dce8fe21cb 100644 --- a/prusti-viper/src/encoder/errors/mod.rs +++ b/prusti-viper/src/encoder/errors/mod.rs @@ -4,14 +4,10 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -pub use self::conversions::*; -pub use self::spanned_encoding_error::*; -pub use self::error_manager::*; -pub use self::encoding_error::*; -pub use self::encoding_error_kind::*; -pub use self::with_span::*; -pub use self::position_manager::*; -pub use self::macros::*; +pub use self::{ + conversions::*, encoding_error::*, encoding_error_kind::*, error_manager::*, macros::*, + position_manager::*, spanned_encoding_error::*, with_span::*, +}; pub use prusti_rustc_interface::errors::MultiSpan; mod conversions; diff --git a/prusti-viper/src/encoder/errors/position_manager.rs b/prusti-viper/src/encoder/errors/position_manager.rs index 5b9757bd3dd..2adbe27367a 100644 --- a/prusti-viper/src/encoder/errors/position_manager.rs +++ b/prusti-viper/src/encoder/errors/position_manager.rs @@ -6,12 +6,11 @@ use std::fmt::Debug; -use vir_crate::polymorphic::Position; -use rustc_hash::FxHashMap; -use prusti_rustc_interface::span::source_map::SourceMap; -use prusti_rustc_interface::errors::MultiSpan; use log::debug; use prusti_interface::data::ProcedureDefId; +use prusti_rustc_interface::{errors::MultiSpan, span::source_map::SourceMap}; +use rustc_hash::FxHashMap; +use vir_crate::polymorphic::Position; /// Mapping from VIR positions to the source code that generated them. /// One VIR position can be involved in multiple errors. If an error needs to refer to a special @@ -26,8 +25,7 @@ pub struct PositionManager<'tcx> { pub(crate) source_span: FxHashMap, } -impl<'tcx> PositionManager<'tcx> -{ +impl<'tcx> PositionManager<'tcx> { pub fn new(codemap: &'tcx SourceMap) -> Self { PositionManager { codemap, @@ -40,15 +38,17 @@ impl<'tcx> PositionManager<'tcx> /// Registers a new span and returns the corresponding VIR position. /// The line and column of the VIR position correspond to the start of the given span. #[tracing::instrument(level = "trace", skip(self), ret)] - pub fn register_span + Debug>(&mut self, def_id: ProcedureDefId, span: T) -> Position { + pub fn register_span + Debug>( + &mut self, + def_id: ProcedureDefId, + span: T, + ) -> Position { let span = span.into(); let pos_id = self.next_pos_id; self.next_pos_id += 1; let pos = if let Some(primary_span) = span.primary_span() { - let lines_info_res = self - .codemap - .span_to_lines(primary_span.source_callsite()); + let lines_info_res = self.codemap.span_to_lines(primary_span.source_callsite()); match lines_info_res { Ok(lines_info) => { if let Some(first_line_info) = lines_info.lines.get(0) { @@ -61,7 +61,10 @@ impl<'tcx> PositionManager<'tcx> } } Err(e) => { - debug!("Error converting primary span of position id {} to lines: {:?}", pos_id, e); + debug!( + "Error converting primary span of position id {} to lines: {:?}", + pos_id, e + ); Position::new(0, 0, pos_id) } } diff --git a/prusti-viper/src/encoder/errors/spanned_encoding_error.rs b/prusti-viper/src/encoder/errors/spanned_encoding_error.rs index 8b6a39adc0c..c27865fa14c 100644 --- a/prusti-viper/src/encoder/errors/spanned_encoding_error.rs +++ b/prusti-viper/src/encoder/errors/spanned_encoding_error.rs @@ -4,9 +4,9 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -use prusti_rustc_interface::errors::MultiSpan; use log::{debug, error}; use prusti_interface::PrustiError; +use prusti_rustc_interface::errors::MultiSpan; use crate::encoder::errors::EncodingErrorKind; use backtrace::Backtrace; @@ -25,15 +25,9 @@ pub type SpannedEncodingResult = Result; impl From for PrustiError { fn from(other: SpannedEncodingError) -> Self { let mut error = match other.error { - EncodingErrorKind::Unsupported(msg) => { - PrustiError::unsupported(msg, *other.span) - } - EncodingErrorKind::Incorrect(msg) => { - PrustiError::incorrect(msg, *other.span) - } - EncodingErrorKind::Internal(msg) => { - PrustiError::internal(msg, *other.span) - } + EncodingErrorKind::Unsupported(msg) => PrustiError::unsupported(msg, *other.span), + EncodingErrorKind::Incorrect(msg) => PrustiError::incorrect(msg, *other.span), + EncodingErrorKind::Internal(msg) => PrustiError::internal(msg, *other.span), }; if let Some(help) = other.help { error = error.set_help(help); @@ -61,10 +55,7 @@ impl SpannedEncodingError { if cfg!(debug_assertions) { debug!("Constructing unsupported error at:\n{:?}", Backtrace::new()); } - SpannedEncodingError::new( - EncodingErrorKind::unsupported(message), - span - ) + SpannedEncodingError::new(EncodingErrorKind::unsupported(message), span) } /// An incorrect usage of Prusti (e.g. call an impure function in a contract) @@ -73,10 +64,7 @@ impl SpannedEncodingError { if cfg!(debug_assertions) { debug!("Constructing incorrect error at:\n{:?}", Backtrace::new()); } - SpannedEncodingError::new( - EncodingErrorKind::incorrect(message), - span - ) + SpannedEncodingError::new(EncodingErrorKind::incorrect(message), span) } /// An internal error of Prusti (e.g. failure of the fold-unfold) @@ -84,10 +72,7 @@ impl SpannedEncodingError { if cfg!(debug_assertions) { error!("Constructing internal error at:\n{:?}", Backtrace::new()); } - SpannedEncodingError::new( - EncodingErrorKind::internal(message), - span - ) + SpannedEncodingError::new(EncodingErrorKind::internal(message), span) } pub fn kind(&self) -> &EncodingErrorKind { diff --git a/prusti-viper/src/encoder/errors/with_span.rs b/prusti-viper/src/encoder/errors/with_span.rs index 18a185de404..498ac9eba61 100644 --- a/prusti-viper/src/encoder/errors/with_span.rs +++ b/prusti-viper/src/encoder/errors/with_span.rs @@ -4,16 +4,19 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -use prusti_rustc_interface::errors::MultiSpan; -use crate::encoder::errors::{SpannedEncodingError, EncodingError}; +use crate::encoder::errors::{EncodingError, SpannedEncodingError}; use log::trace; +use prusti_rustc_interface::errors::MultiSpan; /// Helper trait to convert a `Result` to a /// `Result`. pub trait WithSpan { fn with_span>(self, span: S) -> Result; // FIXME: Make the method names consistent. - fn set_span_with>(self, span_callback: impl Fn() -> S) -> Result; + fn set_span_with>( + self, + span_callback: impl Fn() -> S, + ) -> Result; fn with_default_span>(self, span: S) -> Result; } @@ -24,7 +27,10 @@ impl WithSpan for Result { err.with_span(span) }) } - fn set_span_with>(self, span_callback: impl Fn() -> S) -> Result { + fn set_span_with>( + self, + span_callback: impl Fn() -> S, + ) -> Result { self.map_err(|err| { trace!("Converting a EncodingError to SpannedEncodingError in a Result"); let span = span_callback(); @@ -46,7 +52,10 @@ impl WithSpan for Result { err.with_span(span) }) } - fn set_span_with>(self, span_callback: impl Fn() -> S) -> Result { + fn set_span_with>( + self, + span_callback: impl Fn() -> S, + ) -> Result { self.map_err(|err| { trace!("Converting a EncodingError to SpannedEncodingError in a Result"); let span = span_callback(); diff --git a/prusti-viper/src/encoder/initialisation.rs b/prusti-viper/src/encoder/initialisation.rs index 4f88cfac156..d1e4659876f 100644 --- a/prusti-viper/src/encoder/initialisation.rs +++ b/prusti-viper/src/encoder/initialisation.rs @@ -5,19 +5,26 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/. use crate::encoder::mir_encoder::{MirEncoder, PlaceEncoder}; -/// Module that allows querying the initialisation information. -use vir_crate::polymorphic as vir; -use prusti_interface::environment::mir_analyses::initialization::compute_definitely_initialized; -use prusti_interface::environment::mir_sets::PlaceSet; -use prusti_interface::utils::expand_one_level; -use prusti_rustc_interface::hir::def_id::DefId; -use prusti_rustc_interface::middle::{mir, ty::{self, TyCtxt}}; +use prusti_interface::{ + environment::{ + mir_analyses::initialization::compute_definitely_initialized, mir_sets::PlaceSet, + }, + utils::expand_one_level, +}; +use prusti_rustc_interface::{ + hir::def_id::DefId, + middle::{ + mir, + ty::{self, TyCtxt}, + }, +}; use rustc_hash::{FxHashMap, FxHashSet}; use std::hash::Hash; +/// Module that allows querying the initialisation information. +use vir_crate::polymorphic as vir; use crate::encoder::errors::EncodingResult; - pub struct InitInfo { //mir_acc_before_block: FxHashMap>>, //mir_acc_after_statement: FxHashMap>>, @@ -30,7 +37,7 @@ pub struct InitInfo { fn explode<'tcx>( mir: &mir::Body<'tcx>, tcx: TyCtxt<'tcx>, - place_set: PlaceSet<'tcx> + place_set: PlaceSet<'tcx>, ) -> FxHashSet> { let mut result = FxHashSet::default(); for guide_place in place_set.into_iter() { diff --git a/prusti-viper/src/encoder/loop_encoder.rs b/prusti-viper/src/encoder/loop_encoder.rs index 77635d14f8b..6d4e1daf827 100644 --- a/prusti-viper/src/encoder/loop_encoder.rs +++ b/prusti-viper/src/encoder/loop_encoder.rs @@ -4,14 +4,18 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -use prusti_interface::environment::mir_analyses::initialization::{ - compute_definitely_initialized, DefinitelyInitializedAnalysisResult, +use log::debug; +use prusti_interface::{ + environment::{ + mir_analyses::initialization::{ + compute_definitely_initialized, DefinitelyInitializedAnalysisResult, + }, + mir_sets::PlaceSet, + BasicBlockIndex, LoopAnalysisError, PermissionForest, Procedure, ProcedureLoops, + }, + utils, }; -use prusti_interface::environment::mir_sets::PlaceSet; -use prusti_interface::environment::{BasicBlockIndex, LoopAnalysisError, PermissionForest, ProcedureLoops, Procedure}; -use prusti_interface::utils; use prusti_rustc_interface::middle::{mir, ty}; -use log::debug; pub enum LoopEncoderError { LoopInvariantInBranch(BasicBlockIndex), @@ -24,10 +28,7 @@ pub struct LoopEncoder<'p, 'tcx: 'p> { } impl<'p, 'tcx: 'p> LoopEncoder<'p, 'tcx> { - pub fn new( - procedure: &'p Procedure<'tcx>, - tcx: ty::TyCtxt<'tcx>, - ) -> Self { + pub fn new(procedure: &'p Procedure<'tcx>, tcx: ty::TyCtxt<'tcx>) -> Self { LoopEncoder { procedure, tcx, @@ -72,7 +73,7 @@ impl<'p, 'tcx: 'p> LoopEncoder<'p, 'tcx> { pub fn compute_loop_invariant( &self, bb: BasicBlockIndex, - bb_inv: BasicBlockIndex + bb_inv: BasicBlockIndex, ) -> Result, LoopAnalysisError> { assert!(self.is_loop_head(bb)); @@ -116,8 +117,14 @@ impl<'p, 'tcx: 'p> LoopEncoder<'p, 'tcx> { } // Construct the permission forest. - let forest = - PermissionForest::new(self.procedure.get_mir(), self.tcx, &write_leaves, &mut_borrow_leaves, &read_leaves, &all_places); + let forest = PermissionForest::new( + self.procedure.get_mir(), + self.tcx, + &write_leaves, + &mut_borrow_leaves, + &read_leaves, + &all_places, + ); Ok(forest) } @@ -134,7 +141,7 @@ impl<'p, 'tcx: 'p> LoopEncoder<'p, 'tcx> { #[tracing::instrument(level = "debug", skip(self))] pub fn get_loop_invariant_block( &self, - loop_head: BasicBlockIndex + loop_head: BasicBlockIndex, ) -> Result { let loop_info = self.loops(); debug_assert!(loop_info.is_loop_head(loop_head)); @@ -142,13 +149,13 @@ impl<'p, 'tcx: 'p> LoopEncoder<'p, 'tcx> { let loop_body: Vec = loop_info .get_loop_body(loop_head) - .iter().copied() + .iter() + .copied() .filter(|&bb| !self.procedure.is_spec_block(bb)) .collect(); - let opt_before_invariant_block: Option = loop_body - .iter().copied() - .find(|&bb| { + let opt_before_invariant_block: Option = + loop_body.iter().copied().find(|&bb| { // Find the user-defined invariant loop_info.get_loop_depth(bb) == loop_depth && self.mir()[bb].terminator().successors().any(|succ_bb| { @@ -172,10 +179,12 @@ impl<'p, 'tcx: 'p> LoopEncoder<'p, 'tcx> { // HEURISTIC: place the invariant after the first boolean exit block in a // non-conditional branch. If there is none, place the invariant at the loop head. let loop_exit_blocks = loop_info.get_loop_exit_blocks(loop_head); - let before_invariant_block = loop_exit_blocks.iter().copied() + let before_invariant_block = loop_exit_blocks + .iter() + .copied() .find(|&bb| { self.procedure.successors(bb).len() == 2 - && !loop_info.is_conditional_branch(loop_head, bb) + && !loop_info.is_conditional_branch(loop_head, bb) }) .unwrap_or(loop_head); Ok(before_invariant_block) diff --git a/prusti-viper/src/encoder/mir_encoder/downcast_detector.rs b/prusti-viper/src/encoder/mir_encoder/downcast_detector.rs index 9dd5a21d92f..ae9cbd78468 100644 --- a/prusti-viper/src/encoder/mir_encoder/downcast_detector.rs +++ b/prusti-viper/src/encoder/mir_encoder/downcast_detector.rs @@ -1,12 +1,14 @@ -use prusti_rustc_interface::middle::mir; -use prusti_rustc_interface::target::abi; -use prusti_rustc_interface::middle::mir::visit::Visitor; use prusti_interface::environment::mir_utils::MirPlace; -use rustc_hash::{FxHashSet}; +use prusti_rustc_interface::{ + middle::{mir, mir::visit::Visitor}, + target::abi, +}; +use rustc_hash::FxHashSet; -pub fn detect_downcasts<'tcx>(body: &mir::Body<'tcx>, location: mir::Location) - -> Vec<(MirPlace<'tcx>, abi::VariantIdx)> -{ +pub fn detect_downcasts<'tcx>( + body: &mir::Body<'tcx>, + location: mir::Location, +) -> Vec<(MirPlace<'tcx>, abi::VariantIdx)> { let mut collector = DownCastCollector::default(); collector.visit_location(body, location); let mut downcasts: Vec<_> = collector.downcasts.into_iter().collect(); @@ -17,7 +19,7 @@ pub fn detect_downcasts<'tcx>(body: &mir::Body<'tcx>, location: mir::Location) #[derive(Default)] struct DownCastCollector<'tcx> { - pub downcasts: FxHashSet<(MirPlace<'tcx>, abi::VariantIdx)> + pub downcasts: FxHashSet<(MirPlace<'tcx>, abi::VariantIdx)>, } impl<'tcx> Visitor<'tcx> for DownCastCollector<'tcx> { @@ -31,16 +33,14 @@ impl<'tcx> Visitor<'tcx> for DownCastCollector<'tcx> { self.super_projection_elem(place_ref, elem, context, location); if let mir::PlaceElem::Downcast(_, variant) = elem { - self.downcasts.insert( - ( - // FIXME: Store `PlaceRef`, once `visit_projection_elem` will provide that. - MirPlace { - local: place_ref.local, - projection: place_ref.projection.to_owned(), - }, - variant, - ) - ); + self.downcasts.insert(( + // FIXME: Store `PlaceRef`, once `visit_projection_elem` will provide that. + MirPlace { + local: place_ref.local, + projection: place_ref.projection.to_owned(), + }, + variant, + )); } } } diff --git a/prusti-viper/src/encoder/mir_encoder/mod.rs b/prusti-viper/src/encoder/mir_encoder/mod.rs index 3304c97ea9a..8712faff6e1 100644 --- a/prusti-viper/src/encoder/mir_encoder/mod.rs +++ b/prusti-viper/src/encoder/mir_encoder/mod.rs @@ -6,40 +6,41 @@ use std::fmt::Debug; -use crate::encoder::errors::{ - ErrorCtxt, PanicCause, SpannedEncodingError, EncodingError, WithSpan, - SpannedEncodingResult, EncodingResult +use super::high::types::HighTypeEncoderInterface; +use crate::{ + encoder::{ + errors::{ + EncodingError, EncodingResult, ErrorCtxt, PanicCause, SpannedEncodingError, + SpannedEncodingResult, WithSpan, + }, + mir::{sequences::MirSequencesEncoderInterface, types::MirTypeEncoderInterface}, + snapshot::interface::SnapshotEncoderInterface, + Encoder, + }, + error_internal, error_unsupported, utils, }; -use crate::encoder::Encoder; -use crate::encoder::snapshot::interface::SnapshotEncoderInterface; -use crate::{utils, error_internal, error_unsupported}; -use prusti_common::vir_expr; -use vir_crate::{polymorphic as vir}; -use prusti_common::config; -use prusti_rustc_interface::target::abi; -use prusti_rustc_interface::hir::def_id::DefId; -use prusti_rustc_interface::middle::{mir, ty}; -use prusti_rustc_interface::index::IndexVec; -use prusti_rustc_interface::span::{Span, DUMMY_SP}; -use log::{trace, debug}; +use log::{debug, trace}; +use prusti_common::{config, vir_expr}; use prusti_interface::environment::mir_utils::MirPlace; -use crate::encoder::mir::{ - sequences::MirSequencesEncoderInterface, - types::MirTypeEncoderInterface, +use prusti_rustc_interface::{ + errors::MultiSpan, + hir::def_id::DefId, + index::IndexVec, + middle::{mir, ty}, + span::{Span, DUMMY_SP}, + target::abi, }; -use super::high::types::HighTypeEncoderInterface; -use prusti_rustc_interface::errors::MultiSpan; +use vir_crate::polymorphic as vir; mod downcast_detector; mod place_encoding; -pub use place_encoding::{PlaceEncoding, ExprOrArrayBase}; +pub use place_encoding::{ExprOrArrayBase, PlaceEncoding}; pub static PRECONDITION_LABEL: &str = "pre"; pub static WAND_LHS_LABEL: &str = "lhs"; pub trait PlaceEncoder<'v, 'tcx: 'v> { - fn encoder(&self) -> &Encoder<'v, 'tcx>; fn get_local_ty(&self, local: mir::Local) -> ty::Ty<'tcx>; @@ -50,7 +51,10 @@ pub trait PlaceEncoder<'v, 'tcx: 'v> { format!("{local:?}") } - fn encode_local_high(&self, local: mir::Local) -> SpannedEncodingResult { + fn encode_local_high( + &self, + local: mir::Local, + ) -> SpannedEncodingResult { let var_name = self.encode_local_var_name(local); let typ = self .encoder() @@ -98,10 +102,8 @@ pub trait PlaceEncoder<'v, 'tcx: 'v> { )); } - let (encoded_base, base_ty, opt_variant_index) = self.encode_projection( - local, - &projection[..projection.len() - 1] - )?; + let (encoded_base, base_ty, opt_variant_index) = + self.encode_projection(local, &projection[..projection.len() - 1])?; trace!("base_ty: {:?}", base_ty); let elem = projection.last().unwrap(); @@ -111,8 +113,8 @@ pub trait PlaceEncoder<'v, 'tcx: 'v> { ty::TyKind::Tuple(elems) => { let field_name = format!("tuple_{}", field.index()); let field_ty = elems[field.index()]; - let encoded_field = self.encoder() - .encode_raw_ref_field(field_name, field_ty)?; + let encoded_field = + self.encoder().encode_raw_ref_field(field_name, field_ty)?; let encoded_projection = encoded_base.field(encoded_field); (encoded_projection, field_ty, None) } @@ -149,10 +151,7 @@ pub trait PlaceEncoder<'v, 'tcx: 'v> { } let encoded_field = self .encoder() - .encode_struct_field( - field.ident(tcx).as_str(), - field_ty - )?; + .encode_struct_field(field.ident(tcx).as_str(), field_ty)?; let encoded_projection = encoded_variant.field(encoded_field); (encoded_projection, field_ty, None) } @@ -163,8 +162,8 @@ pub trait PlaceEncoder<'v, 'tcx: 'v> { let field_ty = *proj_field_ty; let field_name = format!("closure_{}", field.index()); - let encoded_field = self.encoder() - .encode_raw_ref_field(field_name, field_ty)?; + let encoded_field = + self.encoder().encode_raw_ref_field(field_name, field_ty)?; let encoded_projection = encoded_base.field(encoded_field); debug!("encoded_projection: {:?}", encoded_projection); @@ -183,17 +182,15 @@ pub trait PlaceEncoder<'v, 'tcx: 'v> { } } - mir::ProjectionElem::Deref => { - match encoded_base.try_into_expr() { - Ok(e) => { - let (e, ty, v) = self.encode_deref(e, base_ty)?; - (PlaceEncoding::Expr(e), ty, v) - } - Err(_) => error_unsupported!( - "mixed dereferencing and array indexing projections are not supported" - ), + mir::ProjectionElem::Deref => match encoded_base.try_into_expr() { + Ok(e) => { + let (e, ty, v) = self.encode_deref(e, base_ty)?; + (PlaceEncoding::Expr(e), ty, v) } - } + Err(_) => error_unsupported!( + "mixed dereferencing and array indexing projections are not supported" + ), + }, mir::ProjectionElem::Downcast(ref adt_def, variant_index) => { debug!("Downcast projection {:?}, {:?}", adt_def, variant_index); @@ -205,8 +202,7 @@ pub trait PlaceEncoder<'v, 'tcx: 'v> { (encoded_base, *cast_ty, None) } - mir::ProjectionElem::Index(_) - | mir::ProjectionElem::ConstantIndex { .. } => { + mir::ProjectionElem::Index(_) | mir::ProjectionElem::ConstantIndex { .. } => { // FIXME: this avoids some code duplication but the nested // matches could probably be cleaner let index: vir::Expr = match elem { @@ -214,11 +210,19 @@ pub trait PlaceEncoder<'v, 'tcx: 'v> { debug!("index: {:?}[{:?}]", encoded_base, idx); self.encode_local(*idx)?.into() } - mir::ProjectionElem::ConstantIndex { offset, from_end: false, .. } => { + mir::ProjectionElem::ConstantIndex { + offset, + from_end: false, + .. + } => { debug!("constantindex: {:?}[{}]", encoded_base, offset); (*offset).into() } - mir::ProjectionElem::ConstantIndex { offset, from_end: true, .. } => { + mir::ProjectionElem::ConstantIndex { + offset, + from_end: true, + .. + } => { debug!("constantindex: {:?}[len - {}]", encoded_base, offset); let offset = *offset as usize; match base_ty.kind() { @@ -228,51 +232,46 @@ pub trait PlaceEncoder<'v, 'tcx: 'v> { } ty::TyKind::Slice(_) => { let slice_type = self.encoder().encode_sequence_types(base_ty)?; - let slice_len = slice_type.len( - self.encoder(), - encoded_base.clone().try_into_expr()?, - ); + let slice_len = slice_type + .len(self.encoder(), encoded_base.clone().try_into_expr()?); vir_expr! { [ slice_len ] - [ vir::Expr::from(offset) ] } } _ => error_unsupported!( - "pattern matching on the end of '{:?} is not supported", base_ty, - ) + "pattern matching on the end of '{:?} is not supported", + base_ty, + ), } } _ => unreachable!(), }; match base_ty.kind() { - ty::TyKind::Array(elem_ty, _) => { - ( - PlaceEncoding::ArrayAccess { - base: Box::new(encoded_base), - index, - encoded_elem_ty: self.encoder().encode_type(*elem_ty)?, - rust_array_ty: base_ty, - }, - *elem_ty, - None, - ) - }, - ty::TyKind::Slice(elem_ty) => { - ( - PlaceEncoding::SliceAccess { - base: Box::new(encoded_base), - index, - encoded_elem_ty: self.encoder().encode_type(*elem_ty)?, - rust_slice_ty: base_ty, - }, - *elem_ty, - None, - ) - }, + ty::TyKind::Array(elem_ty, _) => ( + PlaceEncoding::ArrayAccess { + base: Box::new(encoded_base), + index, + encoded_elem_ty: self.encoder().encode_type(*elem_ty)?, + rust_array_ty: base_ty, + }, + *elem_ty, + None, + ), + ty::TyKind::Slice(elem_ty) => ( + PlaceEncoding::SliceAccess { + base: Box::new(encoded_base), + index, + encoded_elem_ty: self.encoder().encode_type(*elem_ty)?, + rust_slice_ty: base_ty, + }, + *elem_ty, + None, + ), _ => error_unsupported!("index on unsupported type '{:?}'", base_ty), } } - mir::ProjectionElem::Subslice { .. } => error_unsupported!( - "slice patterns are not supported", - ), + mir::ProjectionElem::Subslice { .. } => { + error_unsupported!("slice patterns are not supported",) + } }) } @@ -283,14 +282,12 @@ pub trait PlaceEncoder<'v, 'tcx: 'v> { base_ty: ty::Ty<'tcx>, ) -> EncodingResult<(vir::Expr, ty::Ty<'tcx>, Option)> { Ok(match base_ty.kind() { - ty::TyKind::RawPtr(ty::TypeAndMut { ty, .. }) - | ty::TyKind::Ref(_, ty, _) => { + ty::TyKind::RawPtr(ty::TypeAndMut { ty, .. }) | ty::TyKind::Ref(_, ty, _) => { let access = if encoded_base.is_addr_of() { // Simplify `*&` ==> `` encoded_base.get_parent().unwrap() } else { - let ref_field = self.encoder() - .encode_dereference_field(*ty)?; + let ref_field = self.encoder().encode_dereference_field(*ty)?; encoded_base.field(ref_field) }; (access, *ty, None) @@ -300,8 +297,7 @@ pub trait PlaceEncoder<'v, 'tcx: 'v> { encoded_base.get_parent().unwrap() } else { let field_ty = base_ty.boxed_ty(); - let ref_field = self.encoder() - .encode_dereference_field(field_ty)?; + let ref_field = self.encoder().encode_dereference_field(field_ty)?; encoded_base.field(ref_field) }; (access, base_ty.boxed_ty(), None) @@ -322,7 +318,6 @@ pub trait PlaceEncoder<'v, 'tcx: 'v> { _ => false, } } - } /// Place encoder used when we do not have access to MIR. For example, when @@ -345,15 +340,11 @@ impl<'p, 'v: 'p, 'tcx: 'v> FakeMirEncoder<'p, 'v, 'tcx> { for arg_ty in arg_tys { tys.push(arg_ty); } - Self { - encoder, - tys, - } + Self { encoder, tys } } } impl<'p, 'v: 'p, 'tcx: 'v> PlaceEncoder<'v, 'tcx> for FakeMirEncoder<'p, 'v, 'tcx> { - fn encoder(&self) -> &Encoder<'v, 'tcx> { self.encoder } @@ -376,7 +367,6 @@ pub struct MirEncoder<'p, 'v: 'p, 'tcx: 'v> { } impl<'p, 'v: 'p, 'tcx: 'v> PlaceEncoder<'v, 'tcx> for MirEncoder<'p, 'v, 'tcx> { - fn encoder(&self) -> &Encoder<'v, 'tcx> { self.encoder } @@ -392,11 +382,7 @@ impl<'p, 'v: 'p, 'tcx: 'v> PlaceEncoder<'v, 'tcx> for MirEncoder<'p, 'v, 'tcx> { impl<'p, 'v: 'p, 'tcx: 'v> MirEncoder<'p, 'v, 'tcx> { #[tracing::instrument(name = "MirEncoder::new", level = "trace", skip_all)] - pub fn new( - encoder: &'p Encoder<'v, 'tcx>, - mir: &'p mir::Body<'tcx>, - def_id: DefId, - ) -> Self { + pub fn new(encoder: &'p Encoder<'v, 'tcx>, mir: &'p mir::Body<'tcx>, def_id: DefId) -> Self { MirEncoder { encoder, mir, @@ -406,12 +392,11 @@ impl<'p, 'v: 'p, 'tcx: 'v> MirEncoder<'p, 'v, 'tcx> { /// Returns an `vir::Expr` that corresponds to the value of the operand #[tracing::instrument(level = "trace", skip(self))] - pub fn encode_operand_expr( - &self, - operand: &mir::Operand<'tcx>, - ) -> EncodingResult { + pub fn encode_operand_expr(&self, operand: &mir::Operand<'tcx>) -> EncodingResult { Ok(match operand { - mir::Operand::Constant(expr) => self.encoder.encode_const_expr(expr.ty(), expr.literal)?, + mir::Operand::Constant(expr) => { + self.encoder.encode_const_expr(expr.ty(), expr.literal)? + } &mir::Operand::Copy(place) | &mir::Operand::Move(place) => { // let val_place = self.eval_place(&place)?; // inlined to do try_into_expr @@ -424,29 +409,28 @@ impl<'p, 'v: 'p, 'tcx: 'v> MirEncoder<'p, 'v, 'tcx> { ))?, place_ty, )? - } - // FIXME: Check whether the commented out code is necessary. - // &mir::Operand::Constant(box mir::Constant { - // ty, - // literal: mir::Literal::Promoted { .. }, - // .. - // }) => { - // debug!("Incomplete encoding of promoted literal {:?}", operand); - - // // Generate a function call that leaves the expression undefined. - // let encoded_type = self.encoder.encode_value_type(ty); - // let function_name = - // self.encoder - // .encode_builtin_function_use(BuiltinFunctionKind::Unreachable( - // encoded_type.clone(), - // )); - // let pos = self.encoder.error_manager().register_error( - // // TODO: use a proper span - // self.mir.span, - // ErrorCtxt::PureFunctionCall, - // ); - // vir::Expr::func_app(function_name, vec![], vec![], encoded_type, pos) - // } + } // FIXME: Check whether the commented out code is necessary. + // &mir::Operand::Constant(box mir::Constant { + // ty, + // literal: mir::Literal::Promoted { .. }, + // .. + // }) => { + // debug!("Incomplete encoding of promoted literal {:?}", operand); + + // // Generate a function call that leaves the expression undefined. + // let encoded_type = self.encoder.encode_value_type(ty); + // let function_name = + // self.encoder + // .encode_builtin_function_use(BuiltinFunctionKind::Unreachable( + // encoded_type.clone(), + // )); + // let pos = self.encoder.error_manager().register_error( + // // TODO: use a proper span + // self.mir.span, + // ErrorCtxt::PureFunctionCall, + // ); + // vir::Expr::func_app(function_name, vec![], vec![], encoded_type, pos) + // } }) } @@ -464,9 +448,10 @@ impl<'p, 'v: 'p, 'tcx: 'v> MirEncoder<'p, 'v, 'tcx> { /// Returns an `vir::Type` that corresponds to the type of the value of the operand #[tracing::instrument(level = "trace", skip(self))] - pub fn encode_operand_expr_type(&self, operand: &mir::Operand<'tcx>) - -> EncodingResult - { + pub fn encode_operand_expr_type( + &self, + operand: &mir::Operand<'tcx>, + ) -> EncodingResult { // match operand { // &mir::Operand::Constant(box mir::Constant { ty, .. }) => { // let ty = self.encoder.resolve_typaram(ty); @@ -508,9 +493,9 @@ impl<'p, 'v: 'p, 'tcx: 'v> MirEncoder<'p, 'v, 'tcx> { mir::BinOp::BitAnd if is_bool => vir::Expr::and(left, right), mir::BinOp::BitOr if is_bool => vir::Expr::or(left, right), mir::BinOp::BitXor if is_bool => vir::Expr::xor(left, right), - mir::BinOp::BitAnd | - mir::BinOp::BitOr | - mir::BinOp::BitXor if !config::encode_bitvectors() => { + mir::BinOp::BitAnd | mir::BinOp::BitOr | mir::BinOp::BitXor + if !config::encode_bitvectors() => + { error_unsupported!( "bitwise operations on non-boolean types are experimental and disabled by \ default; use `encode_bitvectors` to enable" @@ -526,11 +511,17 @@ impl<'p, 'v: 'p, 'tcx: 'v> MirEncoder<'p, 'v, 'tcx> { mir::BinOp::BitAnd => vir::Expr::bin_op(vir::BinaryOpKind::BitAnd, left, right), mir::BinOp::BitOr => vir::Expr::bin_op(vir::BinaryOpKind::BitOr, left, right), mir::BinOp::BitXor => vir::Expr::bin_op(vir::BinaryOpKind::BitXor, left, right), - mir::BinOp::ShlUnchecked | mir::BinOp::Shl => vir::Expr::bin_op(vir::BinaryOpKind::Shl, left, right), + mir::BinOp::ShlUnchecked | mir::BinOp::Shl => { + vir::Expr::bin_op(vir::BinaryOpKind::Shl, left, right) + } // https://doc.rust-lang.org/reference/expressions/operator-expr.html#arithmetic-and-logical-binary-operators // Arithmetic right shift on signed integer types, logical right shift on unsigned integer types. - mir::BinOp::ShrUnchecked | mir::BinOp::Shr if is_signed => vir::Expr::bin_op(vir::BinaryOpKind::AShr, left, right), - mir::BinOp::ShrUnchecked | mir::BinOp::Shr => vir::Expr::bin_op(vir::BinaryOpKind::LShr, left, right), + mir::BinOp::ShrUnchecked | mir::BinOp::Shr if is_signed => { + vir::Expr::bin_op(vir::BinaryOpKind::AShr, left, right) + } + mir::BinOp::ShrUnchecked | mir::BinOp::Shr => { + vir::Expr::bin_op(vir::BinaryOpKind::LShr, left, right) + } mir::BinOp::Offset => { error_unsupported!("operation '{:?}' is not supported", op); } @@ -552,7 +543,11 @@ impl<'p, 'v: 'p, 'tcx: 'v> MirEncoder<'p, 'v, 'tcx> { right: vir::Expr, ty: ty::Ty<'tcx>, ) -> EncodingResult { - if !matches!(op, mir::BinOp::Add | mir::BinOp::Sub | mir::BinOp::Mul | mir::BinOp::Shl | mir::BinOp::Shr) || !config::check_overflows() { + if !matches!( + op, + mir::BinOp::Add | mir::BinOp::Sub | mir::BinOp::Mul | mir::BinOp::Shl | mir::BinOp::Shr + ) || !config::check_overflows() + { Ok(false.into()) } else { let result = self.encode_bin_op_expr(op, left, right.clone(), ty)?; @@ -644,7 +639,7 @@ impl<'p, 'v: 'p, 'tcx: 'v> MirEncoder<'p, 'v, 'tcx> { ty::TyKind::Int(ty::IntTy::I128) => 128, ty::TyKind::Int(ty::IntTy::Isize) => { error_unsupported!("unknown size of isize for the overflow check"); - }, + } _ => { error_unsupported!( "overflow checks are unsupported for operation '{:?}' on type '{:?}'", @@ -673,7 +668,7 @@ impl<'p, 'v: 'p, 'tcx: 'v> MirEncoder<'p, 'v, 'tcx> { let encoded_val = match (src_ty.kind(), dst_ty.kind()) { // Numeric casts that cannot fail - | (ty::TyKind::Char, ty::TyKind::Char) + (ty::TyKind::Char, ty::TyKind::Char) | (ty::TyKind::Char, ty::TyKind::Uint(ty::UintTy::U8)) | (ty::TyKind::Char, ty::TyKind::Uint(ty::UintTy::U16)) | (ty::TyKind::Char, ty::TyKind::Uint(ty::UintTy::U32)) @@ -711,8 +706,9 @@ impl<'p, 'v: 'p, 'tcx: 'v> MirEncoder<'p, 'v, 'tcx> { | (ty::TyKind::Uint(ty::UintTy::U64), ty::TyKind::Uint(ty::UintTy::U64)) | (ty::TyKind::Uint(ty::UintTy::U64), ty::TyKind::Uint(ty::UintTy::U128)) | (ty::TyKind::Uint(ty::UintTy::U128), ty::TyKind::Uint(ty::UintTy::U128)) - | (ty::TyKind::Uint(ty::UintTy::Usize), ty::TyKind::Uint(ty::UintTy::Usize)) - => self.encode_operand_expr(operand).with_span(span)?, + | (ty::TyKind::Uint(ty::UintTy::Usize), ty::TyKind::Uint(ty::UintTy::Usize)) => { + self.encode_operand_expr(operand).with_span(span)? + } // Numeric casts where the source value might not fit into the target type (ty::TyKind::Char, ty::TyKind::Int(_)) @@ -722,12 +718,13 @@ impl<'p, 'v: 'p, 'tcx: 'v> MirEncoder<'p, 'v, 'tcx> { | (ty::TyKind::Int(_), ty::TyKind::Uint(_)) | (ty::TyKind::Uint(_), ty::TyKind::Char) | (ty::TyKind::Uint(_), ty::TyKind::Int(_)) - | (ty::TyKind::Uint(_), ty::TyKind::Uint(_)) - => { + | (ty::TyKind::Uint(_), ty::TyKind::Uint(_)) => { let encoded_operand = self.encode_operand_expr(operand).with_span(span)?; if config::check_overflows() { // Check the cast - let function_name = self.encoder.encode_cast_function_use(src_ty, dst_ty) + let function_name = self + .encoder + .encode_cast_function_use(src_ty, dst_ty) .with_span(span)?; let encoded_args = vec![encoded_operand]; let formal_args = vec![vir::LocalVar::new( @@ -752,10 +749,8 @@ impl<'p, 'v: 'p, 'tcx: 'v> MirEncoder<'p, 'v, 'tcx> { _ => { return Err(SpannedEncodingError::unsupported( - format!( - "unsupported cast from type '{src_ty:?}' to type '{dst_ty:?}'" - ), - span + format!("unsupported cast from type '{src_ty:?}' to type '{dst_ty:?}'"), + span, )); } }; @@ -795,7 +790,10 @@ impl<'p, 'v: 'p, 'tcx: 'v> MirEncoder<'p, 'v, 'tcx> { self.mir.source_info(location).span } - pub fn get_downcasts_at_location(&self, location: mir::Location) -> Vec<(MirPlace<'tcx>, abi::VariantIdx)> { + pub fn get_downcasts_at_location( + &self, + location: mir::Location, + ) -> Vec<(MirPlace<'tcx>, abi::VariantIdx)> { downcast_detector::detect_downcasts(self.mir, location) } @@ -805,11 +803,19 @@ impl<'p, 'v: 'p, 'tcx: 'v> MirEncoder<'p, 'v, 'tcx> { } pub fn register_span + Debug>(&self, span: T) -> vir::Position { - self.encoder.error_manager().register_span(self.def_id, span) + self.encoder + .error_manager() + .register_span(self.def_id, span) } - pub fn register_error + Debug>(&self, span: T, error_ctxt: ErrorCtxt) -> vir::Position { - self.encoder.error_manager().register_error(span, error_ctxt, self.def_id) + pub fn register_error + Debug>( + &self, + span: T, + error_ctxt: ErrorCtxt, + ) -> vir::Position { + self.encoder + .error_manager() + .register_error(span, error_ctxt, self.def_id) } /// Return the cause of a call to `begin_panic` @@ -821,15 +827,14 @@ impl<'p, 'v: 'p, 'tcx: 'v> MirEncoder<'p, 'v, 'tcx> { // To classify the cause of the panic it's enough to look at the top 3 macro calls let lookup_size = 3; let env_name = self.encoder.env().name; - let macro_names: Vec = macro_backtrace.iter() + let macro_names: Vec = macro_backtrace + .iter() .take(lookup_size) .filter_map(|x| x.macro_def_id.map(|y| env_name.get_absolute_item_name(y))) .collect(); debug!("macro_names: {:?}", macro_names); - let macro_names_str: Vec<&str> = macro_names.iter() - .map(|x| x.as_str()) - .collect(); + let macro_names_str: Vec<&str> = macro_names.iter().map(|x| x.as_str()).collect(); match ¯o_names_str[..] { ["core::panic::panic_2015", "core::macros::panic", "std::unimplemented"] | ["std::unimplemented", ..] => PanicCause::Unimplemented, @@ -838,7 +843,9 @@ impl<'p, 'v: 'p, 'tcx: 'v> MirEncoder<'p, 'v, 'tcx> { | ["std::unreachable", ..] => PanicCause::Unreachable, ["std::assert", "std::debug_assert", ..] => PanicCause::DebugAssert, ["std::assert", ..] => PanicCause::Assert, - ["std::panic::panic_2015", "std::panic", "std::debug_assert"] => PanicCause::DebugAssert, + ["std::panic::panic_2015", "std::panic", "std::debug_assert"] => { + PanicCause::DebugAssert + } // TODO: assert!(_, "") currently has the same backtrace as panic!() // see https://github.com/rust-lang/rust/issues/82157 //["std::panic::panic_2015", "std::panic", ..] => PanicCause::Assert, diff --git a/prusti-viper/src/encoder/mir_encoder/place_encoding.rs b/prusti-viper/src/encoder/mir_encoder/place_encoding.rs index 23af5ecdb89..8bf9ec6ec66 100644 --- a/prusti-viper/src/encoder/mir_encoder/place_encoding.rs +++ b/prusti-viper/src/encoder/mir_encoder/place_encoding.rs @@ -4,16 +4,12 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. - use std::fmt::Display; use prusti_rustc_interface::middle::ty; use vir_crate::polymorphic as vir; -use crate::encoder::{ - errors::{EncodingError, EncodingResult}, -}; - +use crate::encoder::errors::{EncodingError, EncodingResult}; /// Result of encoding a place #[derive(Debug, PartialEq, Eq, Hash, Clone)] @@ -57,11 +53,12 @@ pub enum ExprOrArrayBase { impl<'tcx> PlaceEncoding<'tcx> { pub fn try_into_expr(self) -> EncodingResult { match self.into_array_base() { - ExprOrArrayBase::Expr(e) => Ok(e), - ExprOrArrayBase::ArrayBase(b) - | ExprOrArrayBase::SliceBase(b) => Err(EncodingError::internal( - format!("PlaceEncoding::try_into_expr called on sequence expr '{b:?}'") - )), + ExprOrArrayBase::Expr(e) => Ok(e), + ExprOrArrayBase::ArrayBase(b) | ExprOrArrayBase::SliceBase(b) => { + Err(EncodingError::internal(format!( + "PlaceEncoding::try_into_expr called on sequence expr '{b:?}'" + ))) + } } } @@ -70,52 +67,59 @@ impl<'tcx> PlaceEncoding<'tcx> { pub fn into_array_base(self) -> ExprOrArrayBase { match self { PlaceEncoding::Expr(e) => ExprOrArrayBase::Expr(e), - PlaceEncoding::FieldAccess { base, field } => { - match base.into_array_base() { - ExprOrArrayBase::Expr(e) => ExprOrArrayBase::Expr(e.field(field)), - base@ExprOrArrayBase::ArrayBase(_) => base, - base@ExprOrArrayBase::SliceBase(_) => base, - } - } - PlaceEncoding::Variant { base, field } => { - match base.into_array_base() { - ExprOrArrayBase::Expr(e) => ExprOrArrayBase::Expr( - vir::Expr::Variant( vir::Variant {base: Box::new(e), variant_index: field, position: vir::Position::default()} ) - ), - base@ExprOrArrayBase::ArrayBase(_) => base, - base@ExprOrArrayBase::SliceBase(_) => base, + PlaceEncoding::FieldAccess { base, field } => match base.into_array_base() { + ExprOrArrayBase::Expr(e) => ExprOrArrayBase::Expr(e.field(field)), + base @ ExprOrArrayBase::ArrayBase(_) => base, + base @ ExprOrArrayBase::SliceBase(_) => base, + }, + PlaceEncoding::Variant { base, field } => match base.into_array_base() { + ExprOrArrayBase::Expr(e) => { + ExprOrArrayBase::Expr(vir::Expr::Variant(vir::Variant { + base: Box::new(e), + variant_index: field, + position: vir::Position::default(), + })) } - } + base @ ExprOrArrayBase::ArrayBase(_) => base, + base @ ExprOrArrayBase::SliceBase(_) => base, + }, PlaceEncoding::ArrayAccess { base, .. } => { // need to check base's into_expr_or_array_base, maybe we're not the outermost // array match base.into_array_base() { ExprOrArrayBase::Expr(e) => ExprOrArrayBase::ArrayBase(e), - base@ExprOrArrayBase::ArrayBase(_) => base, - base@ExprOrArrayBase::SliceBase(_) => base, - } - } - PlaceEncoding::SliceAccess { base, .. } => { - match base.into_array_base() { - ExprOrArrayBase::Expr(e) => ExprOrArrayBase::SliceBase(e), - base@ExprOrArrayBase::ArrayBase(_) => base, - base@ExprOrArrayBase::SliceBase(_) => base, + base @ ExprOrArrayBase::ArrayBase(_) => base, + base @ ExprOrArrayBase::SliceBase(_) => base, } } + PlaceEncoding::SliceAccess { base, .. } => match base.into_array_base() { + ExprOrArrayBase::Expr(e) => ExprOrArrayBase::SliceBase(e), + base @ ExprOrArrayBase::ArrayBase(_) => base, + base @ ExprOrArrayBase::SliceBase(_) => base, + }, } } pub fn field(self, field: vir::Field) -> Self { - PlaceEncoding::FieldAccess { base: Box::new(self), field } + PlaceEncoding::FieldAccess { + base: Box::new(self), + field, + } } pub fn get_type(&self) -> &vir::Type { match self { PlaceEncoding::Expr(ref e) => e.get_type(), PlaceEncoding::FieldAccess { ref field, .. } => &field.typ, - PlaceEncoding::ArrayAccess { ref encoded_elem_ty, .. } => encoded_elem_ty, + PlaceEncoding::ArrayAccess { + ref encoded_elem_ty, + .. + } => encoded_elem_ty, PlaceEncoding::Variant { ref field, .. } => &field.typ, - PlaceEncoding::SliceAccess { ref encoded_elem_ty, .. } => encoded_elem_ty, + PlaceEncoding::SliceAccess { + ref encoded_elem_ty, + .. + } => encoded_elem_ty, } } @@ -124,7 +128,10 @@ impl<'tcx> PlaceEncoding<'tcx> { let field_name = format!("enum_{index}"); let field = vir::Field::new(field_name, self.get_type().clone().variant(index)); - PlaceEncoding::Variant { base: Box::new(self), field } + PlaceEncoding::Variant { + base: Box::new(self), + field, + } } } diff --git a/prusti-viper/src/encoder/mir_successor.rs b/prusti-viper/src/encoder/mir_successor.rs index 603a12ad34f..51e44f74c4e 100644 --- a/prusti-viper/src/encoder/mir_successor.rs +++ b/prusti-viper/src/encoder/mir_successor.rs @@ -1,5 +1,5 @@ -use vir_crate::polymorphic::{CfgBlockIndex, Expr, Successor}; use prusti_interface::environment::BasicBlockIndex; +use vir_crate::polymorphic::{CfgBlockIndex, Expr, Successor}; #[derive(Eq, PartialEq, Clone, Debug)] pub enum MirSuccessor { diff --git a/prusti-viper/src/encoder/mirror_function_encoder.rs b/prusti-viper/src/encoder/mirror_function_encoder.rs index 1c09951cc30..bd02f48dc83 100644 --- a/prusti-viper/src/encoder/mirror_function_encoder.rs +++ b/prusti-viper/src/encoder/mirror_function_encoder.rs @@ -4,13 +4,11 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -use rustc_hash::{FxHashSet}; use prusti_rustc_interface::hir::def_id::DefId; +use rustc_hash::FxHashSet; use vir_crate::polymorphic::{self as vir}; - - const MIRROR_DOMAIN_NAME: &str = "MirrorDomain"; pub struct MirrorEncoder { @@ -33,7 +31,6 @@ impl MirrorEncoder { } } - pub fn get_domain(&self) -> Option<&vir::Domain> { if self.encoded.is_empty() { None @@ -58,11 +55,7 @@ impl MirrorEncoder { self.encode_mirror_axiomatized(def_id, function); } - fn encode_mirror_simple( - &mut self, - _def_id: DefId, - function: &mut vir::Function, - ) { + fn encode_mirror_simple(&mut self, _def_id: DefId, function: &mut vir::Function) { // create mirror function let mirror_func = vir::DomainFunc { name: format!("mirror_simple${}", function.name), @@ -75,33 +68,31 @@ impl MirrorEncoder { // add postcondition to the original function // [result == mirror(args), true] - function.posts.push(vir::Expr::InhaleExhale( vir::InhaleExhale { - inhale_expr: Box::new(vir::Expr::eq_cmp( - vir::Expr::local( - vir::LocalVar::new("__result", function.return_type.clone()), - ), - vir::Expr::domain_func_app( - mirror_func.clone(), - function.formal_args.iter() - .cloned() - .map(vir::Expr::local) - .collect(), - ), - )), - exhale_expr: Box::new(true.into()), - position: vir::Position::default(), - })); + function + .posts + .push(vir::Expr::InhaleExhale(vir::InhaleExhale { + inhale_expr: Box::new(vir::Expr::eq_cmp( + vir::Expr::local(vir::LocalVar::new("__result", function.return_type.clone())), + vir::Expr::domain_func_app( + mirror_func.clone(), + function + .formal_args + .iter() + .cloned() + .map(vir::Expr::local) + .collect(), + ), + )), + exhale_expr: Box::new(true.into()), + position: vir::Position::default(), + })); // add mirror function to mirror domain self.domain.functions.push(mirror_func); } // TODO: ... - fn encode_mirror_axiomatized( - &mut self, - _def_id: DefId, - _function: &mut vir::Function, - ) {} + fn encode_mirror_axiomatized(&mut self, _def_id: DefId, _function: &mut vir::Function) {} } // ------------------------------ diff --git a/prusti-viper/src/encoder/name_interner.rs b/prusti-viper/src/encoder/name_interner.rs index f92f45b61a9..aca0eab302e 100644 --- a/prusti-viper/src/encoder/name_interner.rs +++ b/prusti-viper/src/encoder/name_interner.rs @@ -28,7 +28,11 @@ impl NameInterner { /// The `readable_names` must not collide with past or future `full_unique_name`s, except for /// the `full_unique_name` passed in the same call. #[tracing::instrument(level = "debug", skip(self), ret)] - pub fn intern + Debug>(&mut self, full_unique_name: S, readable_names: &[S]) -> String { + pub fn intern + Debug>( + &mut self, + full_unique_name: S, + readable_names: &[S], + ) -> String { let full_unique_name = full_unique_name.as_ref(); debug_assert!(!readable_names.iter().any(|r| r.as_ref() == "")); @@ -41,7 +45,7 @@ impl NameInterner { // Check that readable names passed in the past are not equal to the current full name. debug_assert!( self.name_to_symbol.contains_key(full_unique_name) - || !self.used_symbols.contains(full_unique_name) + || !self.used_symbols.contains(full_unique_name) ); // Return the symbol, if we already interned the full name @@ -49,12 +53,14 @@ impl NameInterner { return symbol.clone(); } - let symbol = readable_names.iter() + let symbol = readable_names + .iter() .find(|r| !self.used_symbols.contains(r.as_ref())) .map(|r| r.as_ref()) .unwrap_or(full_unique_name); self.used_symbols.insert(symbol.to_string()); - self.name_to_symbol.insert(full_unique_name.to_string(), symbol.to_string()); + self.name_to_symbol + .insert(full_unique_name.to_string(), symbol.to_string()); symbol.to_string() } @@ -88,7 +94,10 @@ mod tests { #[test] fn test_full_name_eq_readable_names() { let mut interner = NameInterner::new(); - assert_eq!(interner.intern("my$first$name", &["my$first$name"]), "my$first$name"); + assert_eq!( + interner.intern("my$first$name", &["my$first$name"]), + "my$first$name" + ); } #[test] @@ -102,13 +111,31 @@ mod tests { #[test] fn test_multiple_readable_names() { let mut interner = NameInterner::new(); - assert_eq!(interner.intern("my$first$name", &["name", "first$name"]), "name"); - assert_eq!(interner.intern("my$first$name", &["name", "first$name"]), "name"); - assert_eq!(interner.intern("my$second$name", &["name", "second$name"]), "second$name"); + assert_eq!( + interner.intern("my$first$name", &["name", "first$name"]), + "name" + ); + assert_eq!( + interner.intern("my$first$name", &["name", "first$name"]), + "name" + ); + assert_eq!( + interner.intern("my$second$name", &["name", "second$name"]), + "second$name" + ); assert_eq!(interner.intern("my$second$name", &[]), "second$name"); - assert_eq!(interner.intern("my$first$name", &["name", "first$name"]), "name"); - assert_eq!(interner.intern("my$third$name", &["name", "third$name"]), "third$name"); - assert_eq!(interner.intern("another$second$name", &["name", "second$name"]), "another$second$name"); + assert_eq!( + interner.intern("my$first$name", &["name", "first$name"]), + "name" + ); + assert_eq!( + interner.intern("my$third$name", &["name", "third$name"]), + "third$name" + ); + assert_eq!( + interner.intern("another$second$name", &["name", "second$name"]), + "another$second$name" + ); assert_eq!(interner.intern("my$second$name", &[]), "second$name"); } diff --git a/prusti-viper/src/encoder/places.rs b/prusti-viper/src/encoder/places.rs index 6ab6c1e8bbd..508f4b324ae 100644 --- a/prusti-viper/src/encoder/places.rs +++ b/prusti-viper/src/encoder/places.rs @@ -4,10 +4,11 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -use prusti_rustc_interface::middle::mir; -use prusti_rustc_interface::middle::ty::Ty; -use prusti_rustc_interface::index::{Idx, IndexVec}; -use std::{iter}; +use prusti_rustc_interface::{ + index::{Idx, IndexVec}, + middle::{mir, ty::Ty}, +}; +use std::iter; /// A local variable used as an abstraction over both real Rust MIR local /// variables and temporary variables used in encoder. diff --git a/prusti-viper/src/encoder/procedure_encoder.rs b/prusti-viper/src/encoder/procedure_encoder.rs index 1d4183c5198..fbfd26fd802 100644 --- a/prusti-viper/src/encoder/procedure_encoder.rs +++ b/prusti-viper/src/encoder/procedure_encoder.rs @@ -4,84 +4,87 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -use crate::encoder::mir::spans::interface::SpanInterface; -use crate::encoder::builtin_encoder::{BuiltinMethodKind}; -use crate::encoder::errors::{ - SpannedEncodingError, ErrorCtxt, EncodingError, WithSpan, - EncodingResult, SpannedEncodingResult +use super::{ + counterexamples::DiscriminantsStateInterface, high::generics::HighGenericsEncoderInterface, }; -use crate::encoder::errors::error_manager::PanicCause; -use crate::encoder::foldunfold; -use crate::encoder::high::types::HighTypeEncoderInterface; -use crate::encoder::initialisation::InitInfo; -use crate::encoder::loop_encoder::{LoopEncoder, LoopEncoderError}; -use crate::encoder::mir_encoder::{MirEncoder, FakeMirEncoder, PlaceEncoder, PlaceEncoding, ExprOrArrayBase}; -use crate::encoder::mir_encoder::PRECONDITION_LABEL; -use crate::encoder::mir_successor::MirSuccessor; -use crate::encoder::places::{Local, LocalVariableManager, Place}; -use crate::encoder::Encoder; -use crate::encoder::snapshot::interface::SnapshotEncoderInterface; -use crate::encoder::mir::procedures::encoder::specification_blocks::SpecificationBlocks; -use crate::error_unsupported; +use crate::{ + encoder::{ + builtin_encoder::BuiltinMethodKind, + errors::{ + error_manager::PanicCause, EncodingError, EncodingErrorKind, EncodingResult, ErrorCtxt, + SpannedEncodingError, SpannedEncodingResult, WithSpan, + }, + foldunfold, + high::types::HighTypeEncoderInterface, + initialisation::InitInfo, + loop_encoder::{LoopEncoder, LoopEncoderError}, + mir::{ + contracts::{ContractsEncoderInterface, ProcedureContract}, + procedures::encoder::specification_blocks::SpecificationBlocks, + pure::{PureFunctionEncoderInterface, SpecificationEncoderInterface}, + sequences::MirSequencesEncoderInterface, + spans::interface::SpanInterface, + specifications::SpecificationsInterface, + type_invariants::TypeInvariantEncoderInterface, + types::MirTypeEncoderInterface, + }, + mir_encoder::{ + ExprOrArrayBase, FakeMirEncoder, MirEncoder, PlaceEncoder, PlaceEncoding, + PRECONDITION_LABEL, + }, + mir_successor::MirSuccessor, + places::{Local, LocalVariableManager, Place}, + snapshot::interface::SnapshotEncoderInterface, + Encoder, + }, + error_unsupported, + utils::is_reference, +}; +use ::log::{debug, trace}; use prusti_common::{ config, utils::to_string::ToString, - vir::{ToGraphViz, fixes::fix_ghost_vars}, - vir_local, vir_expr, vir_stmt -}; -use vir_crate::{ - polymorphic::{ - self as vir, - compute_identifier, - borrows::Borrow, - collect_assigned_vars, - CfgBlockIndex, ExprIterator, Successor, Type}, + vir::{fixes::fix_ghost_vars, ToGraphViz}, + vir_expr, vir_local, vir_stmt, }; use prusti_interface::{ data::ProcedureDefId, environment::{ - borrowck::facts, + borrowck::{facts, regions::PlaceRegionsError}, + mir_utils::SliceOrArrayRef, polonius_info::{ LoanPlaces, PoloniusInfo, PoloniusInfoError, ReborrowingDAG, ReborrowingDAGNode, ReborrowingKind, ReborrowingZombity, }, BasicBlockIndex, LoopAnalysisError, PermissionKind, Procedure, }, - PrustiError, + specs::{ + typed, + typed::{Pledge, SpecificationItem}, + }, + utils, PrustiError, }; -use std::{collections::{BTreeMap}, convert::TryInto, fmt::{Debug, Write}}; -use prusti_interface::utils; -use prusti_rustc_interface::index::IndexSlice; -use prusti_rustc_interface::middle::mir::Mutability; -use prusti_rustc_interface::middle::mir; -use prusti_rustc_interface::middle::mir::{TerminatorKind}; -use prusti_rustc_interface::middle::ty::{self, GenericArgsRef}; -use prusti_rustc_interface::target::abi::{FieldIdx, Integer}; -use rustc_hash::{FxHashMap, FxHashSet}; -use prusti_rustc_interface::span::Span; -use prusti_rustc_interface::errors::MultiSpan; -use prusti_interface::specs::typed; -use ::log::{trace, debug}; -use prusti_interface::environment::borrowck::regions::PlaceRegionsError; -use crate::encoder::errors::EncodingErrorKind; -use prusti_interface::specs::typed::{Pledge, SpecificationItem}; -use vir_crate::polymorphic::Float; -use crate::utils::is_reference; -use crate::encoder::mir::{ - sequences::MirSequencesEncoderInterface, - contracts::{ - ContractsEncoderInterface, - ProcedureContract, +use prusti_rustc_interface::{ + errors::MultiSpan, + index::IndexSlice, + middle::{ + mir, + mir::{Mutability, TerminatorKind}, + ty::{self, GenericArgsRef}, }, - pure::PureFunctionEncoderInterface, - types::MirTypeEncoderInterface, - pure::SpecificationEncoderInterface, - specifications::SpecificationsInterface, - type_invariants::TypeInvariantEncoderInterface, + span::Span, + target::abi::{FieldIdx, Integer}, +}; +use rustc_hash::{FxHashMap, FxHashSet}; +use std::{ + collections::BTreeMap, + convert::TryInto, + fmt::{Debug, Write}, +}; +use vir_crate::polymorphic::{ + self as vir, borrows::Borrow, collect_assigned_vars, compute_identifier, CfgBlockIndex, + ExprIterator, Float, Successor, Type, }; -use super::high::generics::HighGenericsEncoderInterface; -use super::counterexamples::DiscriminantsStateInterface; -use prusti_interface::environment::mir_utils::SliceOrArrayRef; pub struct ProcedureEncoder<'p, 'v: 'p, 'tcx: 'v> { encoder: &'p Encoder<'v, 'tcx>, @@ -120,7 +123,8 @@ pub struct ProcedureEncoder<'p, 'v: 'p, 'tcx: 'v> { FxHashMap, FxHashMap)>, /// A map that stores local variables used to preserve the value of a place accross the loop /// when we cannot do that by using permissions. - pure_var_for_preserving_value_map: FxHashMap>, + pure_var_for_preserving_value_map: + FxHashMap>, /// Information about which places are definitely initialised. init_info: InitInfo, /// Mapping from old expressions to ghost variables with which they were replaced. @@ -138,7 +142,7 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { #[tracing::instrument(name = "ProcedureEncoder::new", level = "debug", skip_all, fields(proc_def_id = ?procedure.get_id()))] pub fn new( encoder: &'p Encoder<'v, 'tcx>, - procedure: &'p Procedure<'tcx> + procedure: &'p Procedure<'tcx>, ) -> SpannedEncodingResult { let mir = procedure.get_mir(); let proc_def_id = procedure.get_id(); @@ -148,7 +152,8 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { let init_info = InitInfo::new(mir, tcx, proc_def_id, &mir_encoder) .with_default_span(procedure.get_span())?; - let specification_blocks = SpecificationBlocks::build(encoder.env().query, mir, procedure, false); + let specification_blocks = + SpecificationBlocks::build(encoder.env().query, mir, procedure, false); let cfg_method = vir::CfgMethod::new( // method name @@ -221,8 +226,8 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { ) -> SpannedEncodingResult<()> { let block = &self.mir[bb]; let _ = self.try_encode_assert(bb, block, encoded_statements)? - || self.try_encode_assume(bb, block, encoded_statements)? - || self.try_encode_refute(bb, block, encoded_statements)?; + || self.try_encode_assume(bb, block, encoded_statements)? + || self.try_encode_refute(bb, block, encoded_statements)?; Ok(()) } @@ -241,13 +246,11 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { if self.encoder.get_prusti_assumption(cl_def_id).is_none() { return Ok(false); } - let assume_expr = self.encoder.encode_invariant(self.mir, bb, self.proc_def_id, cl_substs)?; + let assume_expr = + self.encoder + .encode_invariant(self.mir, bb, self.proc_def_id, cl_substs)?; - let assume_stmt = vir::Stmt::Inhale( - vir::Inhale { - expr: assume_expr - } - ); + let assume_stmt = vir::Stmt::Inhale(vir::Inhale { expr: assume_expr }); encoded_statements.push(assume_stmt); @@ -278,14 +281,14 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { .encoder .get_definition_span(assertion.assertion.to_def_id()); - let assert_expr = self.encoder.encode_invariant(self.mir, bb, self.proc_def_id, cl_substs)?; + let assert_expr = + self.encoder + .encode_invariant(self.mir, bb, self.proc_def_id, cl_substs)?; - let assert_stmt = vir::Stmt::Assert( - vir::Assert { - expr: assert_expr, - position: self.register_error(span, ErrorCtxt::Panic(PanicCause::Assert)) - } - ); + let assert_stmt = vir::Stmt::Assert(vir::Assert { + expr: assert_expr, + position: self.register_error(span, ErrorCtxt::Panic(PanicCause::Assert)), + }); encoded_statements.push(assert_stmt); @@ -316,14 +319,14 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { .encoder .get_definition_span(refutation.refutation.to_def_id()); - let refute_expr = self.encoder.encode_invariant(self.mir, bb, self.proc_def_id, cl_substs)?; + let refute_expr = + self.encoder + .encode_invariant(self.mir, bb, self.proc_def_id, cl_substs)?; - let refute_stmt = vir::Stmt::Refute( - vir::Refute { - expr: refute_expr, - position: self.register_error(span, ErrorCtxt::Panic(PanicCause::Refute)) - } - ); + let refute_stmt = vir::Stmt::Refute(vir::Refute { + expr: refute_expr, + position: self.register_error(span, ErrorCtxt::Panic(PanicCause::Refute)), + }); encoded_statements.push(refute_stmt); @@ -340,11 +343,15 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { variable, } => { let msg = if self.mir.local_decls[variable].is_user_variable() { - "creation of loan 'FIXME: extract variable name' in loop is unsupported".to_string() + "creation of loan 'FIXME: extract variable name' in loop is unsupported" + .to_string() } else { "creation of temporary loan in loop is unsupported".to_string() }; - SpannedEncodingError::unsupported(msg, self.mir_encoder.get_span_of_basic_block(loop_head)) + SpannedEncodingError::unsupported( + msg, + self.mir_encoder.get_span_of_basic_block(loop_head), + ) } PoloniusInfoError::LoansInNestedLoops(location1, _loop1, _location2, _loop2) => { @@ -362,11 +369,13 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { ) } - PoloniusInfoError::MultipleMagicWandsPerLoop(location) => SpannedEncodingError::unsupported( - "the creation of loans in this loop is not supported \ + PoloniusInfoError::MultipleMagicWandsPerLoop(location) => { + SpannedEncodingError::unsupported( + "the creation of loans in this loop is not supported \ (MultipleMagicWandsPerLoop)", - self.mir.source_info(location).span, - ), + self.mir.source_info(location).span, + ) + } PoloniusInfoError::MagicWandHasNoRepresentativeLoan(location) => { SpannedEncodingError::unsupported( @@ -376,10 +385,7 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { ) } - PoloniusInfoError::PlaceRegionsError( - PlaceRegionsError::Unsupported(msg), - span, - ) => { + PoloniusInfoError::PlaceRegionsError(PlaceRegionsError::Unsupported(msg), span) => { SpannedEncodingError::unsupported(msg, span) } @@ -402,7 +408,8 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { let mir_span = self.mir.span; // Retrieve the contract - let procedure_contract = self.encoder + let procedure_contract = self + .encoder .get_procedure_contract_for_def(self.proc_def_id, self.substs) .with_span(mir_span)?; assert_one_magic_wand(procedure_contract.borrow_infos.len()).with_span(mir_span)?; @@ -413,9 +420,9 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { let name = self.mir_encoder.encode_local_var_name(local); let typ = self .encoder - .encode_type(self.mir_encoder.get_local_ty(local)).unwrap(); // will panic if attempting to encode unsupported type - self.cfg_method - .add_formal_return(&name, typ) + .encode_type(self.mir_encoder.get_local_ty(local)) + .unwrap(); // will panic if attempting to encode unsupported type + self.cfg_method.add_formal_return(&name, typ) } // Preprocess loops @@ -437,8 +444,12 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { // Load Polonius info self.polonius_info = Some( - PoloniusInfo::new(self.encoder.env(), self.procedure, &self.cached_loop_invariant_block) - .map_err(|err| self.translate_polonius_error(err))?, + PoloniusInfo::new( + self.encoder.env(), + self.procedure, + &self.cached_loop_invariant_block, + ) + .map_err(|err| self.translate_polonius_error(err))?, ); // Initialize CFG blocks @@ -470,7 +481,7 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { .register_span(self.mir_encoder.get_span_of_basic_block(bbi)); self.cfg_method.add_stmt( start_cfg_block, - vir::Stmt::Assign( vir::Assign { + vir::Stmt::Assign(vir::Assign { target: vir::Expr::local(executed_flag_var.clone()).set_pos(bb_pos), source: false.into(), kind: vir::AssignKind::Copy, @@ -491,9 +502,7 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { )?; if !unresolved_edges.is_empty() { return Err(SpannedEncodingError::internal( - format!( - "there are unresolved CFG edges in the encoding: {unresolved_edges:?}" - ), + format!("there are unresolved CFG edges in the encoding: {unresolved_edges:?}"), mir_span, )); } @@ -505,8 +514,8 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { ); // Prepare assertions to check specification refinement - let (precondition_weakening, postcondition_strengthening) - = self.encode_spec_refinement(PRECONDITION_LABEL)?; + let (precondition_weakening, postcondition_strengthening) = + self.encode_spec_refinement(PRECONDITION_LABEL)?; // Encode preconditions self.encode_preconditions(start_cfg_block, precondition_weakening)?; @@ -523,8 +532,7 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { let local_ty = self.locals.get_type(*local); let typ = self.encoder.encode_type(local_ty).unwrap(); // will panic if attempting to encode unsupported type let var_name = self.locals.get_name(*local); - self.cfg_method - .add_local_var(&var_name, typ); + self.cfg_method.add_local_var(&var_name, typ); } self.check_vir()?; @@ -544,7 +552,9 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { } // Patch snapshots - self.cfg_method = self.encoder.patch_snapshots_method(self.cfg_method) + self.cfg_method = self + .encoder + .patch_snapshots_method(self.cfg_method) .with_span(mir_span)?; // Add fold/unfold @@ -554,10 +564,7 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { .iter() .map(|(loan, location)| (loan.index().into(), *location)) .collect(); - let method_pos = self.register_error( - self.mir.span, - ErrorCtxt::Unexpected - ); + let method_pos = self.register_error(self.mir.span, ErrorCtxt::Unexpected); let method_with_fold_unfold = foldunfold::add_fold_unfold( self.encoder, self.cfg_method, @@ -565,19 +572,15 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { &self.cfg_blocks_map, method_pos, ) - .map_err(|foldunfold_error| { - match foldunfold_error { - foldunfold::FoldUnfoldError::Unsupported(msg) => { - SpannedEncodingError::unsupported(msg, mir_span) - } - - _ => SpannedEncodingError::internal( - format!( - "cannot generate fold-unfold Viper statements. {foldunfold_error}", - ), - mir_span, - ), + .map_err(|foldunfold_error| match foldunfold_error { + foldunfold::FoldUnfoldError::Unsupported(msg) => { + SpannedEncodingError::unsupported(msg, mir_span) } + + _ => SpannedEncodingError::internal( + format!("cannot generate fold-unfold Viper statements. {foldunfold_error}",), + mir_span, + ), })?; // Fix variable declarations. @@ -681,7 +684,8 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { matches!( expr, vir::Expr::Const(vir::ConstExpr { - value: vir::Const::Bool(true), .. + value: vir::Const::Bool(true), + .. }) ) } @@ -703,14 +707,28 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { } impl<'a, 'b, 'c> ExprFolder for FindFnApps<'a, 'b, 'c> { fn fold_func_app(&mut self, expr: vir::FuncApp) -> vir::Expr { - let vir::FuncApp { function_name, type_arguments, arguments, formal_arguments, return_type, .. } = expr; + let vir::FuncApp { + function_name, + type_arguments, + arguments, + formal_arguments, + return_type, + .. + } = expr; if self.recurse { - let identifier: vir::FunctionIdentifier = - compute_identifier(&function_name, &type_arguments, &formal_arguments, &return_type).into(); + let identifier: vir::FunctionIdentifier = compute_identifier( + &function_name, + &type_arguments, + &formal_arguments, + &return_type, + ) + .into(); let pres = self.encoder.get_function(&identifier).unwrap().pres.clone(); // Avoid recursively collecting preconditions: they should be self-framing anyway self.recurse = false; - let pres: vir::Expr = pres.into_iter().fold(true.into(), |acc, expr| vir_expr! { [acc] && [expr] }); + let pres: vir::Expr = pres + .into_iter() + .fold(true.into(), |acc, expr| vir_expr! { [acc] && [expr] }); self.push_precond(pres, Some(function_name)); self.recurse = true; @@ -724,16 +742,27 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { // We only care about the exhale part (e.g. for `walk_exhale`) self.fold(*expr.exhale_expr) } - fn fold_predicate_access_predicate(&mut self, expr: vir::PredicateAccessPredicate) -> vir::Expr { + fn fold_predicate_access_predicate( + &mut self, + expr: vir::PredicateAccessPredicate, + ) -> vir::Expr { self.fold(*expr.argument); true.into() } - fn fold_field_access_predicate(&mut self, expr: vir::FieldAccessPredicate) -> vir::Expr { + fn fold_field_access_predicate( + &mut self, + expr: vir::FieldAccessPredicate, + ) -> vir::Expr { self.fold(*expr.base); true.into() } fn fold_bin_op(&mut self, expr: vir::BinOp) -> vir::Expr { - let vir::BinOp { op_kind, left, right, position } = expr; + let vir::BinOp { + op_kind, + left, + right, + position, + } = expr; let left = self.fold_boxed(left); let right = self.fold_boxed(right); match op_kind { @@ -742,27 +771,38 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { vir::BinaryOpKind::Or if is_const_true(&left) => *left, vir::BinaryOpKind::Or if is_const_true(&right) => *right, _ => vir::Expr::BinOp(vir::BinOp { - op_kind, left, right, position, + op_kind, + left, + right, + position, }), } } } let mut walker = FindFnApps { - recurse: true, preconds: Vec::new(), encoder: self.encoder + recurse: true, + preconds: Vec::new(), + encoder: self.encoder, }; walker.walk(stmt); walker.preconds } fn block_preconditions(&self, block: &CfgBlockIndex) -> Vec<(Option, vir::Expr)> { let bb = &self.cfg_method.basic_blocks[block.block_index]; - let mut preconds: Vec<_> = bb.stmts.iter().flat_map(|stmt| self.stmt_preconditions(stmt)).collect(); + let mut preconds: Vec<_> = bb + .stmts + .iter() + .flat_map(|stmt| self.stmt_preconditions(stmt)) + .collect(); match &bb.successor { Successor::Undefined => (), Successor::Return => (), Successor::Goto(cbi) => preconds.extend(self.block_preconditions(cbi)), Successor::GotoSwitch(succs, def) => { preconds.extend( - succs.iter().flat_map(|cond_bb| self.block_preconditions(&cond_bb.1)) + succs + .iter() + .flat_map(|cond_bb| self.block_preconditions(&cond_bb.1)), ); preconds.extend(self.block_preconditions(def)); } @@ -834,9 +874,9 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { .get_loop_body(loop_head) .iter() .copied() - .filter( - |&bb| self.procedure.is_reachable_block(bb) && !self.procedure.is_spec_block(bb) - ) + .filter(|&bb| { + self.procedure.is_reachable_block(bb) && !self.procedure.is_spec_block(bb) + }) .collect(); // Identify important blocks @@ -844,13 +884,15 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { let loop_exit_blocks_set: FxHashSet<_> = loop_exit_blocks.iter().cloned().collect(); let before_invariant_block: BasicBlockIndex = self.cached_loop_invariant_block[&loop_head]; let before_inv_block_pos = loop_body - .iter().copied() + .iter() + .copied() .position(|bb| bb == before_invariant_block) .unwrap(); let after_inv_block_pos = 1 + before_inv_block_pos; // Find boolean switch exit blocks before the invariant let boolean_exit_blocks_before_inv: Vec<_> = loop_body[0..after_inv_block_pos] - .iter().copied() + .iter() + .copied() .filter(|bb| loop_exit_blocks_set.contains(bb)) .filter(|&bb| self.procedure.successors(bb).len() == 2) .collect(); @@ -932,8 +974,14 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { heads.push(first_b1_head); // Calculate if `G` and `B1` are safe to include as the first `body_invariant!(...)` - let mut preconds = first_g_head.map(|cbi| self.block_preconditions(&cbi)).unwrap_or_default(); - preconds.extend(first_b1_head.map(|cbi| self.block_preconditions(&cbi)).unwrap_or_default()); + let mut preconds = first_g_head + .map(|cbi| self.block_preconditions(&cbi)) + .unwrap_or_default(); + preconds.extend( + first_b1_head + .map(|cbi| self.block_preconditions(&cbi)) + .unwrap_or_default(), + ); // Build the "invariant" CFG block (start - G - B1 - *invariant* - B2 - G - B1 - end) // (1) checks the loop invariant on entry @@ -958,7 +1006,7 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { ); heads.push(Some(inv_pre_block)); self.cfg_method - .set_successor(inv_pre_block, vir::Successor::Goto(inv_post_block_perms)); + .set_successor(inv_pre_block, vir::Successor::Goto(inv_post_block_perms)); { let stmts = self.encode_loop_invariant_exhale_stmts(loop_head, before_invariant_block, false)?; @@ -966,13 +1014,18 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { } // We'll add later more statements at the end of inv_pre_block, to havoc local variables let fnspec_span = { - let (stmts, fnspec_span) = - self.encode_loop_invariant_inhale_fnspec_stmts(loop_head, before_invariant_block, false)?; - self.cfg_method.add_stmts(inv_post_block_fnspc, stmts); fnspec_span + let (stmts, fnspec_span) = self.encode_loop_invariant_inhale_fnspec_stmts( + loop_head, + before_invariant_block, + false, + )?; + self.cfg_method.add_stmts(inv_post_block_fnspc, stmts); + fnspec_span }; { - let stmts = - self.encode_loop_invariant_inhale_perm_stmts(loop_head, before_invariant_block, false).with_span(fnspec_span)?; + let stmts = self + .encode_loop_invariant_inhale_perm_stmts(loop_head, before_invariant_block, false) + .with_span(fnspec_span)?; self.cfg_method.add_stmts(inv_post_block_perms, stmts); } @@ -1002,27 +1055,50 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { Some((mid_g, mid_b1)) } else { // Cannot add loop guard to loop invariant - let fn_names: Vec<_> = preconds.iter().filter_map(|(name, _)| name.as_ref()).map(|name| { - if let Some(rust_name) = name.strip_prefix("f_") { - return rust_name - }; - name.strip_prefix("m_").unwrap_or(name) - }).collect(); + let fn_names: Vec<_> = preconds + .iter() + .filter_map(|(name, _)| name.as_ref()) + .map(|name| { + if let Some(rust_name) = name.strip_prefix("f_") { + return rust_name; + }; + name.strip_prefix("m_").unwrap_or(name) + }) + .collect(); let warning_msg = if fn_names.is_empty() { "the loop guard was not automatically added as a `body_invariant!(...)`, consider doing this manually".to_string() } else { "the loop guard was not automatically added as a `body_invariant!(...)`, \ - due to the following pure functions with preconditions: [".to_string() + &fn_names.join(", ") + "]" + due to the following pure functions with preconditions: [" + .to_string() + + &fn_names.join(", ") + + "]" }; // Span of loop guard - let span_lg = loop_guard_evaluation.last().map(|bb| self.mir_encoder.get_span_of_basic_block(*bb)); + let span_lg = loop_guard_evaluation + .last() + .map(|bb| self.mir_encoder.get_span_of_basic_block(*bb)); // Span of entire loop body before inv; the last elem (if any) will be the `body_invariant!(...)` bb - let span_lb = loop_body_before_inv.iter().rev().skip(1).map(|bb| self.mir_encoder.get_span_of_basic_block(*bb)) - .fold(None, |acc: Option, span| Some(acc.map(|other| - if span.ctxt() == other.ctxt() { span.to(other) } else { other } - ).unwrap_or(span)) ); + let span_lb = loop_body_before_inv + .iter() + .rev() + .skip(1) + .map(|bb| self.mir_encoder.get_span_of_basic_block(*bb)) + .fold(None, |acc: Option, span| { + Some( + acc.map(|other| { + if span.ctxt() == other.ctxt() { + span.to(other) + } else { + other + } + }) + .unwrap_or(span), + ) + }); // Multispan to highlight both - let span = MultiSpan::from_spans(vec![span_lg, span_lb].into_iter().flatten().collect()); + let span = + MultiSpan::from_spans(vec![span_lg, span_lb].into_iter().flatten().collect()); // It's only a warning so we might as well emit it straight away PrustiError::warning(warning_msg, span).emit(&self.encoder.env().diagnostic); None @@ -1065,16 +1141,13 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { ))], ); { - let stmts = self.encode_loop_invariant_exhale_stmts( - loop_head, - before_invariant_block, - true - )?; + let stmts = + self.encode_loop_invariant_exhale_stmts(loop_head, before_invariant_block, true)?; self.cfg_method.add_stmts(end_body_block, stmts); } self.cfg_method.add_stmt( end_body_block, - vir::Stmt::Inhale( vir::Inhale {expr: false.into()} ), + vir::Stmt::Inhale(vir::Inhale { expr: false.into() }), ); heads.push(Some(end_body_block)); @@ -1109,20 +1182,24 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { if let Some(((mid_g_head, mid_g_edges), (mid_b1_head, mid_b1_edges))) = mid_groups { let mid_b1_block = mid_b1_head.unwrap_or(inv_post_block_fnspc); // Link edges of "invariant_perm" (start - G - B1 - *invariant_perm* - G - B1 - invariant_fnspec - B2 - G - B1 - end) - self.cfg_method - .set_successor(inv_post_block_perms, vir::Successor::Goto(mid_g_head.unwrap_or(mid_b1_block))); + self.cfg_method.set_successor( + inv_post_block_perms, + vir::Successor::Goto(mid_g_head.unwrap_or(mid_b1_block)), + ); // We know that there is at least one loop iteration of B2, thus it is safe to assume // that anything beforehand couldn't have exited the loop. Here we use // `self.cfg_method.set_successor(..., Successor::Return)` as the same as `assume false` for (curr_block, target) in &mid_g_edges { if self.loop_encoder.get_loop_depth(*target) < loop_depth { - self.cfg_method.set_successor(*curr_block, Successor::Return); + self.cfg_method + .set_successor(*curr_block, Successor::Return); } } - let mid_g_edges = mid_g_edges.into_iter().filter(|(_, target)| - self.loop_encoder.get_loop_depth(*target) >= loop_depth - ).collect::>(); + let mid_g_edges = mid_g_edges + .into_iter() + .filter(|(_, target)| self.loop_encoder.get_loop_depth(*target) >= loop_depth) + .collect::>(); // Link edges from the mid G group (start - G - B1 - invariant_perm - *G* - B1 - invariant_fnspec - B2 - G - B1 - end) still_unresolved_edges.extend(self.encode_unresolved_edges(mid_g_edges, |bb| { if bb == after_guard_block { @@ -1136,12 +1213,14 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { // that anything beforehand couldn't have exited the loop. for (curr_block, target) in &mid_b1_edges { if self.loop_encoder.get_loop_depth(*target) < loop_depth { - self.cfg_method.set_successor(*curr_block, Successor::Return); + self.cfg_method + .set_successor(*curr_block, Successor::Return); } } - let mid_b1_edges = mid_b1_edges.into_iter().filter(|(_, target)| - self.loop_encoder.get_loop_depth(*target) >= loop_depth - ).collect::>(); + let mid_b1_edges = mid_b1_edges + .into_iter() + .filter(|(_, target)| self.loop_encoder.get_loop_depth(*target) >= loop_depth) + .collect::>(); // Link edges from the mid B1 group (start - G - B1 - invariant_perm - G - *B1* - invariant_fnspec - B2 - G - B1 - end) still_unresolved_edges.extend(self.encode_unresolved_edges(mid_b1_edges, |bb| { if bb == after_inv_block { @@ -1152,8 +1231,10 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { })?); } else { // Link edges of "invariant_perm" (start - G - B1 - *invariant_perm* - invariant_fnspec - B2 - G - B1 - end) - self.cfg_method - .set_successor(inv_post_block_perms, vir::Successor::Goto(inv_post_block_fnspc)); + self.cfg_method.set_successor( + inv_post_block_perms, + vir::Successor::Goto(inv_post_block_fnspc), + ); } // Link edges of "invariant" (start - G - B1 - *invariant* - B2 - G - B1 - end) @@ -1210,13 +1291,18 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { vir::Type::Snapshot(_) => BuiltinMethodKind::HavocRef, vir::Type::Seq(_) => BuiltinMethodKind::HavocRef, vir::Type::Map(_) => BuiltinMethodKind::HavocRef, - vir::Type::Ref => return Err(SpannedEncodingError::internal( - format!("unexpected type of local variable {var:?}"), - self.mir.span, - )), + vir::Type::Ref => { + return Err(SpannedEncodingError::internal( + format!("unexpected type of local variable {var:?}"), + self.mir.span, + )) + } }; - let stmt = vir::Stmt::MethodCall( vir::MethodCall { - method_name: self.encoder.encode_builtin_method_use(builtin_method).with_span(loop_head_span)?, + let stmt = vir::Stmt::MethodCall(vir::MethodCall { + method_name: self + .encoder + .encode_builtin_method_use(builtin_method) + .with_span(loop_head_span)?, arguments: vec![], targets: vec![var], }); @@ -1253,10 +1339,8 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { .insert(curr_block); if self.loop_encoder.is_loop_head(bbi) { - self.cfg_method.add_stmt( - curr_block, - vir::Stmt::comment("This is a loop head"), - ); + self.cfg_method + .add_stmt(curr_block, vir::Stmt::comment("This is a loop head")); } self.encode_execution_flag(bbi, curr_block)?; @@ -1319,7 +1403,7 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { let executed_flag_var = self.cfg_block_has_been_executed[&bbi].clone(); self.cfg_method.add_stmt( cfg_block, - vir::Stmt::Assign( vir::Assign { + vir::Stmt::Assign(vir::Assign { target: vir::Expr::local(executed_flag_var).set_pos(pos), source: true.into(), kind: vir::AssignKind::Copy, @@ -1407,9 +1491,10 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { Err(err) => { let unsupported_msg = match err.kind() { EncodingErrorKind::Unsupported(msg) - if config::allow_unreachable_unsupported_code() => { + if config::allow_unreachable_unsupported_code() => + { msg.to_string() - }, + } _ => { // Propagate the error return Err(err); @@ -1425,13 +1510,11 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { }; let stmts = vec![ vir::Stmt::comment(head_stmt), - vir::Stmt::comment( - format!("Unsupported feature: {unsupported_msg}") - ), - vir::Stmt::Assert( vir::Assert { + vir::Stmt::comment(format!("Unsupported feature: {unsupported_msg}")), + vir::Stmt::Assert(vir::Assert { expr: false.into(), position: pos, - }) + }), ]; (stmts, Some(MirSuccessor::Kill)) } @@ -1461,48 +1544,54 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { mir::StatementKind::Assign(box (lhs, ref rhs)) => { // Array access on the LHS should always be mutable (idx is always calculated // before, and just a separate local variable here) - let (lhs_place_encoding, ty, _) = self.mir_encoder.encode_place(lhs).with_span(span)?; + let (lhs_place_encoding, ty, _) = + self.mir_encoder.encode_place(lhs).with_span(span)?; match lhs_place_encoding { - PlaceEncoding::SliceAccess { box base, index, rust_slice_ty: rust_ty, .. } | - PlaceEncoding::ArrayAccess { box base, index, rust_array_ty: rust_ty, .. } => { + PlaceEncoding::SliceAccess { + box base, + index, + rust_slice_ty: rust_ty, + .. + } + | PlaceEncoding::ArrayAccess { + box base, + index, + rust_array_ty: rust_ty, + .. + } => { // Current stmt is of the form `arr[idx] = val`. This does not have an expiring // temporary variable, so we encode it differently from indexing into an array. - self.encode_array_direct_assign( - base, - index, - rust_ty, - rhs, - location, - )? + self.encode_array_direct_assign(base, index, rust_ty, rhs, location)? } _ => { - let (encoded_lhs, pre_stmts) = self.postprocess_place_encoding(lhs_place_encoding, ArrayAccessKind::Mutable(None, location)) + let (encoded_lhs, pre_stmts) = self + .postprocess_place_encoding( + lhs_place_encoding, + ArrayAccessKind::Mutable(None, location), + ) .with_span(span)?; stmts.extend(pre_stmts); - self.encode_assign( - encoded_lhs, - rhs, - ty, - location, - )? + self.encode_assign(encoded_lhs, rhs, ty, location)? } } } - ref x => return Err(SpannedEncodingError::unsupported( - format!("unsupported statement kind: {x:?}"), - span, - )), + ref x => { + return Err(SpannedEncodingError::unsupported( + format!("unsupported statement kind: {x:?}"), + span, + )) + } }; stmts.extend(encoding_stmts); Ok(self.set_stmts_default_pos(stmts, stmt.source_info.span)) } fn set_stmts_default_pos(&self, stmts: Vec, default_span: Span) -> Vec { - let pos = self.encoder.error_manager().register_span(self.proc_def_id, default_span); - stmts - .into_iter() - .map(|s| s.set_default_pos(pos)) - .collect() + let pos = self + .encoder + .error_manager() + .register_span(self.proc_def_id, default_span); + stmts.into_iter().map(|s| s.set_default_pos(pos)).collect() } /// Encode assignment of RHS to LHS, depending on what kind of thing the RHS is @@ -1519,107 +1608,56 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { mir::Rvalue::Use(ref operand) => { self.encode_assign_operand(&encoded_lhs, operand, location)? } - mir::Rvalue::Aggregate(ref aggregate, ref operands) => { - self.encode_assign_aggregate( - &encoded_lhs, - ty, - aggregate, - operands.as_slice(), - location - )? - }, + mir::Rvalue::Aggregate(ref aggregate, ref operands) => self.encode_assign_aggregate( + &encoded_lhs, + ty, + aggregate, + operands.as_slice(), + location, + )?, mir::Rvalue::BinaryOp(op, box (ref left, ref right)) => { - self.encode_assign_binary_op( - op, - left, - right, - encoded_lhs, - ty, - location - )? + self.encode_assign_binary_op(op, left, right, encoded_lhs, ty, location)? + } + mir::Rvalue::CheckedBinaryOp(op, box (ref left, ref right)) => { + self.encode_assign_checked_binary_op(op, left, right, encoded_lhs, ty, location)? } - mir::Rvalue::CheckedBinaryOp(op, box (ref left, ref right)) => self - .encode_assign_checked_binary_op( - op, - left, - right, - encoded_lhs, - ty, - location, - )?, mir::Rvalue::UnaryOp(op, ref operand) => { - self.encode_assign_unary_op( - op, - operand, - encoded_lhs, - ty, - location - )? + self.encode_assign_unary_op(op, operand, encoded_lhs, ty, location)? } mir::Rvalue::NullaryOp(ref op, op_ty) => { - self.encode_assign_nullary_op( - op, - op_ty, - encoded_lhs, - ty, - location - )? + self.encode_assign_nullary_op(op, op_ty, encoded_lhs, ty, location)? } mir::Rvalue::Discriminant(src) => { - self.encode_assign_discriminant( - src, - location, - encoded_lhs, - ty - )? + self.encode_assign_discriminant(src, location, encoded_lhs, ty)? } mir::Rvalue::Ref(_region, mir_borrow_kind, place) => { - self.encode_assign_ref( - mir_borrow_kind, - place, - location, - encoded_lhs, - ty - )? + self.encode_assign_ref(mir_borrow_kind, place, location, encoded_lhs, ty)? } - mir::Rvalue::Cast(mir::CastKind::PointerExposeAddress, ref operand, dst_ty) | - mir::Rvalue::Cast(mir::CastKind::PointerFromExposedAddress, ref operand, dst_ty) | - mir::Rvalue::Cast(mir::CastKind::IntToInt, ref operand, dst_ty) => { - self.encode_cast( - operand, - dst_ty, - encoded_lhs, - ty, - location, - )? + mir::Rvalue::Cast(mir::CastKind::PointerExposeAddress, ref operand, dst_ty) + | mir::Rvalue::Cast(mir::CastKind::PointerFromExposedAddress, ref operand, dst_ty) + | mir::Rvalue::Cast(mir::CastKind::IntToInt, ref operand, dst_ty) => { + self.encode_cast(operand, dst_ty, encoded_lhs, ty, location)? } mir::Rvalue::Len(place) => { - self.encode_assign_sequence_len( - encoded_lhs, - place, - ty, - location, - )? + self.encode_assign_sequence_len(encoded_lhs, place, ty, location)? } - mir::Rvalue::Repeat(ref operand, times) => { - self.encode_assign_array_repeat_initializer( + mir::Rvalue::Repeat(ref operand, times) => self + .encode_assign_array_repeat_initializer( encoded_lhs, operand, times, ty, location, - )? - } - mir::Rvalue::Cast(mir::CastKind::PointerCoercion(ty::adjustment::PointerCoercion::Unsize), ref operand, cast_ty) => { + )?, + mir::Rvalue::Cast( + mir::CastKind::PointerCoercion(ty::adjustment::PointerCoercion::Unsize), + ref operand, + cast_ty, + ) => { let rhs_ty = self.mir_encoder.get_operand_ty(operand); if rhs_ty.is_array_ref() && cast_ty.is_slice_ref() { trace!("slice: operand={:?}, ty={:?}", operand, cast_ty); - self.encode_assign_slice( - encoded_lhs, - operand, - cast_ty, - location, - )? + self.encode_assign_slice(encoded_lhs, operand, cast_ty, location)? } else { return Err(SpannedEncodingError::unsupported( format!("unsizing a {rhs_ty} into a {cast_ty} is not supported"), @@ -1627,15 +1665,17 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { )); } } - mir::Rvalue::Cast(mir::CastKind::PointerCoercion(_), _, _) | - mir::Rvalue::Cast(mir::CastKind::DynStar, _, _) => { + mir::Rvalue::Cast(mir::CastKind::PointerCoercion(_), _, _) + | mir::Rvalue::Cast(mir::CastKind::DynStar, _, _) => { return Err(SpannedEncodingError::unsupported( - "raw pointers are not supported", span + "raw pointers are not supported", + span, )); } mir::Rvalue::Cast(cast_kind, _, _) => { return Err(SpannedEncodingError::unsupported( - format!("casts {cast_kind:?} are not supported"), span + format!("casts {cast_kind:?} are not supported"), + span, )); } mir::Rvalue::AddressOf(_, _) => { @@ -1645,16 +1685,12 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { } mir::Rvalue::ThreadLocalRef(_) => { return Err(SpannedEncodingError::unsupported( - "references to thread-local storage are not supported", span + "references to thread-local storage are not supported", + span, )); } mir::Rvalue::ShallowInitBox(_, op_ty) => { - self.encode_assign_box( - op_ty, - encoded_lhs, - ty, - location, - )? + self.encode_assign_box(op_ty, encoded_lhs, ty, location)? } mir::Rvalue::CopyForDeref(ref place) => { self.encode_assign_operand(&encoded_lhs, &mir::Operand::Copy(*place), location)? @@ -1676,12 +1712,22 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { /// Encode the lhs and the rhs of the assignment that create the loan #[tracing::instrument(level = "debug", skip(self))] - fn encode_loan_places(&mut self, loan_places: &LoanPlaces<'tcx>) -> SpannedEncodingResult<(vir::Expr, Option, bool, Vec)> { + fn encode_loan_places( + &mut self, + loan_places: &LoanPlaces<'tcx>, + ) -> SpannedEncodingResult<(vir::Expr, Option, bool, Vec)> { let location = loan_places.location; let span = self.mir_encoder.get_span_of_location(location); - let (expiring_base, mut stmts, expiring_ty, _) = self.encode_place(loan_places.dest, ArrayAccessKind::Mutable(None, location), location)?; - trace!("expiring_base: {:?}", (&expiring_base, &stmts, &expiring_ty)); + let (expiring_base, mut stmts, expiring_ty, _) = self.encode_place( + loan_places.dest, + ArrayAccessKind::Mutable(None, location), + location, + )?; + trace!( + "expiring_base: {:?}", + (&expiring_base, &stmts, &expiring_ty) + ); // the original encoding of arrays is with a sort-of magic temporary variable, so // `postprocess_place_encoding` will return `i32` here instead of Array$3$i32. so here @@ -1691,12 +1737,19 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { let (rhs_place_encoding, ..) = self.mir_encoder.encode_place(rhs_place).unwrap(); if let PlaceEncoding::ArrayAccess { .. } = rhs_place_encoding { // encode expiry of the array borrow - let (expired_expr, regained_array, wand_rhs) = self.array_magic_wand_at[&location].clone(); + let (expired_expr, regained_array, wand_rhs) = + self.array_magic_wand_at[&location].clone(); // expiring base is something like ref$i32, so we need .val_ref.val_int - let deref = self.encoder.encode_value_expr(expiring_base.clone(), expiring_ty).with_span(span)?; + let deref = self + .encoder + .encode_value_expr(expiring_base.clone(), expiring_ty) + .with_span(span)?; let target_ty = expiring_ty.peel_refs(); - let expiring_base_value = self.encoder.encode_value_expr(deref, target_ty).with_span(span)?; + let expiring_base_value = self + .encoder + .encode_value_expr(deref, target_ty) + .with_span(span)?; // the original magic wand refered to the temporary variable that we created for array // encoding. the expiry here refers to the non-temporary rust variable, so we need @@ -1707,25 +1760,31 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { // so there's no LHS. instead, we add a label just before the inhale, and refer to // that let new_lhs_label = self.cfg_method.get_fresh_label_name(); - stmts.push( - vir::Stmt::label(new_lhs_label.clone()) - ); + stmts.push(vir::Stmt::label(new_lhs_label.clone())); - let wand_rhs_patched_lhs = wand_rhs - .map_old_expr_label(|label| if label == "lhs" { + let wand_rhs_patched_lhs = wand_rhs.map_old_expr_label(|label| { + if label == "lhs" { trace!("{} -> {}", label, new_lhs_label); new_lhs_label.clone() } else { label } - ); + }); - let expiring_base_pred = self.mir_encoder.encode_place_predicate_permission(expiring_base.clone(), vir::PermAmount::Write).unwrap(); - stmts.push(vir_stmt!{ exhale [expiring_base_pred] }); + let expiring_base_pred = self + .mir_encoder + .encode_place_predicate_permission( + expiring_base.clone(), + vir::PermAmount::Write, + ) + .unwrap(); + stmts.push(vir_stmt! { exhale [expiring_base_pred] }); - let arr_pred = vir::Expr::pred_permission(regained_array.clone(), vir::PermAmount::Write).unwrap(); - stmts.push(vir_stmt!{ inhale [arr_pred] }); - stmts.push(vir_stmt!{ inhale [wand_rhs_patched_lhs] }); + let arr_pred = + vir::Expr::pred_permission(regained_array.clone(), vir::PermAmount::Write) + .unwrap(); + stmts.push(vir_stmt! { inhale [arr_pred] }); + stmts.push(vir_stmt! { inhale [wand_rhs_patched_lhs] }); // NOTE: the third tuple elem is called is_mut in // `construct_vir_reborrowing_node_for_assignment`, and is currently only used to @@ -1737,10 +1796,17 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { } } - let mut encode = |rhs_place, stmts: &mut Vec, array_encode_kind| -> SpannedEncodingResult<_> { - let (restored, pre_stmts, _, _) = self.encode_place(rhs_place, array_encode_kind, location)?; + let mut encode = |rhs_place, + stmts: &mut Vec, + array_encode_kind| + -> SpannedEncodingResult<_> { + let (restored, pre_stmts, _, _) = + self.encode_place(rhs_place, array_encode_kind, location)?; stmts.extend(pre_stmts); - let ref_field = self.encoder.encode_value_field(expiring_ty).with_span(span)?; + let ref_field = self + .encoder + .encode_value_field(expiring_ty) + .with_span(span)?; let expiring = expiring_base.clone().field(ref_field.clone()); Ok((expiring, restored, ref_field)) }; @@ -1751,32 +1817,43 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { mir::BorrowKind::Mut { .. } => true, _ => return Err(Self::unsupported_borrow_kind(mir_borrow_kind).with_span(span)), }; - let array_encode_kind = if is_mut { ArrayAccessKind::Mutable(None, location) } else { ArrayAccessKind::Shared }; + let array_encode_kind = if is_mut { + ArrayAccessKind::Mutable(None, location) + } else { + ArrayAccessKind::Shared + }; let (expiring, restored, _) = encode(rhs_place, &mut stmts, array_encode_kind)?; assert_eq!(expiring.get_type(), restored.get_type()); (expiring, Some(restored), is_mut, stmts) } mir::Rvalue::Use(mir::Operand::Move(rhs_place)) => { - let (expiring, restored_base, ref_field) = encode(rhs_place, &mut stmts, ArrayAccessKind::Shared)?; + let (expiring, restored_base, ref_field) = + encode(rhs_place, &mut stmts, ArrayAccessKind::Shared)?; let restored = restored_base.field(ref_field); assert_eq!(expiring.get_type(), restored.get_type()); (expiring, Some(restored), true, stmts) } mir::Rvalue::Use(mir::Operand::Copy(rhs_place)) => { - let (expiring, restored_base, ref_field) = encode(rhs_place, &mut stmts, ArrayAccessKind::Shared)?; + let (expiring, restored_base, ref_field) = + encode(rhs_place, &mut stmts, ArrayAccessKind::Shared)?; let restored = restored_base.field(ref_field); assert_eq!(expiring.get_type(), restored.get_type()); (expiring, Some(restored), false, stmts) } - mir::Rvalue::Cast(mir::CastKind::PointerCoercion(ty::adjustment::PointerCoercion::Unsize), ref operand, ty) => { + mir::Rvalue::Cast( + mir::CastKind::PointerCoercion(ty::adjustment::PointerCoercion::Unsize), + ref operand, + ty, + ) => { trace!("cast: operand={:?}, ty={:?}", operand, ty); let place = match *operand { mir::Operand::Move(place) => place, mir::Operand::Copy(place) => place, _ => unreachable!("operand: {:?}", operand), }; - let (restored, r_stmts, ..) = self.encode_place(place, ArrayAccessKind::Shared, location)?; + let (restored, r_stmts, ..) = + self.encode_place(place, ArrayAccessKind::Shared, location)?; stmts.extend(r_stmts); (expiring_base, Some(restored), false, stmts) @@ -1785,12 +1862,15 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { mir::Rvalue::Use(mir::Operand::Constant(ref expr)) => { // TODO: Encoding of string literals is not yet supported, so // do not return an expression in restored here. - let restored: Option = - if is_str(expr.ty()) { - None - } else { - Some(self.encoder.encode_const_expr(expr.ty(), expr.literal).with_span(span)?) - }; + let restored: Option = if is_str(expr.ty()) { + None + } else { + Some( + self.encoder + .encode_const_expr(expr.ty(), expr.literal) + .with_span(span)?, + ) + }; (expiring_base, restored, false, stmts) } @@ -1807,13 +1887,13 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { is_in_package_stmt: bool, ) -> Vec { let mut stmts = if let Some(var) = self.old_to_ghost_var.get(&rhs) { - vec![vir::Stmt::Assign( vir::Assign { + vec![vir::Stmt::Assign(vir::Assign { target: var.clone(), source: lhs.clone(), kind: vir::AssignKind::Move, })] } else { - vec![vir::Stmt::TransferPerm( vir::TransferPerm { + vec![vir::Stmt::TransferPerm(vir::TransferPerm { left: lhs.clone(), right: rhs.clone(), unchecked: false, @@ -1821,8 +1901,9 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { }; if self.check_foldunfold_state && !is_in_package_stmt { - let pos = self.register_error(self.mir.source_info(location).span, ErrorCtxt::Unexpected); - stmts.push(vir::Stmt::Assert( vir::Assert { + let pos = + self.register_error(self.mir.source_info(location).span, ErrorCtxt::Unexpected); + stmts.push(vir::Stmt::Assert(vir::Assert { expr: vir::Expr::eq_cmp(lhs, rhs), position: pos, })); @@ -1832,17 +1913,17 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { } fn encode_obtain(&mut self, expr: vir::Expr, pos: vir::Position) -> Vec { - let mut stmts = vec![ - vir::Stmt::Obtain( vir::Obtain { - expr: expr.clone(), - position: pos, - }) - ]; + let mut stmts = vec![vir::Stmt::Obtain(vir::Obtain { + expr: expr.clone(), + position: pos, + })]; if self.check_foldunfold_state { let new_pos = self.encoder.error_manager().duplicate_position(pos); - self.encoder.error_manager().set_error(new_pos, ErrorCtxt::Unexpected); - stmts.push(vir::Stmt::Assert( vir::Assert { + self.encoder + .error_manager() + .set_error(new_pos, ErrorCtxt::Unexpected); + stmts.push(vir::Stmt::Assert(vir::Assert { expr, position: new_pos, })); @@ -1853,17 +1934,19 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { /// A borrow is mutable if it was a MIR unique borrow, a move of /// a borrow, or a argument of a function. - fn is_mutable_borrow(&self, loan: facts::Loan) - -> EncodingResult - { + fn is_mutable_borrow(&self, loan: facts::Loan) -> EncodingResult { if let Some(stmt) = self.polonius_info().get_assignment_for_loan(loan)? { Ok(match stmt.kind { mir::StatementKind::Assign(box (_, ref rhs)) => match rhs { - &mir::Rvalue::Ref(_, mir::BorrowKind::Shared, _) | - &mir::Rvalue::Use(mir::Operand::Copy(_)) => false, - &mir::Rvalue::Ref(_, mir::BorrowKind::Mut { .. }, _) | - &mir::Rvalue::Use(mir::Operand::Move(_)) => true, - &mir::Rvalue::Cast(mir::CastKind::PointerCoercion(ty::adjustment::PointerCoercion::Unsize), _, _ty) => false, + &mir::Rvalue::Ref(_, mir::BorrowKind::Shared, _) + | &mir::Rvalue::Use(mir::Operand::Copy(_)) => false, + &mir::Rvalue::Ref(_, mir::BorrowKind::Mut { .. }, _) + | &mir::Rvalue::Use(mir::Operand::Move(_)) => true, + &mir::Rvalue::Cast( + mir::CastKind::PointerCoercion(ty::adjustment::PointerCoercion::Unsize), + _, + _ty, + ) => false, &mir::Rvalue::Use(mir::Operand::Constant(_)) => false, x => unreachable!("{:?}", x), }, @@ -1905,11 +1988,9 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { is_in_package_stmt, )?, ReborrowingKind::Call { loan, .. } => { - if let Some(slice_expiry_node) = self.construct_vir_reborrowing_node_for_slice( - loan, - node, - location, - )? { + if let Some(slice_expiry_node) = + self.construct_vir_reborrowing_node_for_slice(loan, node, location)? + { slice_expiry_node } else { self.construct_vir_reborrowing_node_for_call( @@ -1917,7 +1998,7 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { loan, node, location, - is_in_package_stmt + is_in_package_stmt, )? } } @@ -1968,33 +2049,33 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { let loan_location = self.polonius_info().get_loan_location(&loan); trace!("loan_location: {:?}", loan_location); - let loan_places = self.polonius_info().get_loan_places(&loan) + let loan_places = self + .polonius_info() + .get_loan_places(&loan) .map_err(EncodingError::from) .with_span(span)?; trace!("loan_places: {:?}", loan_places); - Ok(if let Some(regained) = self.slice_created_at.get(&loan_location) { - let guard = self.construct_location_guard(loan_location); - trace!("guard: {:?}", guard); - trace!("regained: {:?}", regained); - Some( - vir::borrows::Node::new( + Ok( + if let Some(regained) = self.slice_created_at.get(&loan_location) { + let guard = self.construct_location_guard(loan_location); + trace!("guard: {:?}", guard); + trace!("regained: {:?}", regained); + Some(vir::borrows::Node::new( guard, node.loan.index().into(), convert_loans_to_borrows(&node.reborrowing_loans), convert_loans_to_borrows(&node.reborrowed_loans), - vec![ - vir::Stmt::comment("hi"), - ], + vec![vir::Stmt::comment("hi")], vec![regained.clone()], Vec::new(), Vec::new(), None, - ) - ) - } else { - None - }) + )) + } else { + None + }, + ) } #[tracing::instrument(level = "trace", skip(self, _mir_dag))] @@ -2011,11 +2092,14 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { let node_is_leaf = node.reborrowed_loans.is_empty(); let loan_location = self.polonius_info().get_loan_location(&loan); - let loan_places = self.polonius_info().get_loan_places(&loan) + let loan_places = self + .polonius_info() + .get_loan_places(&loan) .map_err(EncodingError::from) - .with_span(span)?.unwrap(); - let (expiring, restored, is_mut, mut stmts) = self.encode_loan_places(&loan_places) - .with_span(span)?; + .with_span(span)? + .unwrap(); + let (expiring, restored, is_mut, mut stmts) = + self.encode_loan_places(&loan_places).with_span(span)?; let borrowed_places = restored.clone().into_iter().collect(); trace!("construct_vir_reborrowing_node_for_assignment(loan={:?}, loan_places={:?}, expiring={:?}, restored={:?}, stmts={:?}", loan, loan_places, expiring, restored, stmts); @@ -2023,12 +2107,18 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { // Move the permissions from the "in loans" ("reborrowing loans") to the current loan if node.incoming_zombies && restored.is_some() { - let lhs_label = self.get_label_after_location(loan_location)?.unwrap().to_string(); + let lhs_label = self + .get_label_after_location(loan_location)? + .unwrap() + .to_string(); for &in_loan in node.reborrowing_loans.iter() { // TODO: Is this the correct span? if self.is_mutable_borrow(in_loan).with_span(span)? { let in_location = self.polonius_info().get_loan_location(&in_loan); - let in_label = self.get_label_after_location(in_location)?.unwrap().to_string(); + let in_label = self + .get_label_after_location(in_location)? + .unwrap() + .to_string(); used_lhs_label = true; stmts.extend(self.encode_transfer_permissions( expiring.clone().old(in_label), @@ -2106,9 +2196,11 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { // Get the borrow information. if !self.procedure_contracts.contains_key(&loan_location) { return Err(SpannedEncodingError::internal( - format!("there is no procedure contract for loan {loan:?}. This could happen if you \ - are chaining pure functions, which is not fully supported."), - span + format!( + "there is no procedure contract for loan {loan:?}. This could happen if you \ + are chaining pure functions, which is not fully supported." + ), + span, )); } let (contract, fake_exprs) = self.procedure_contracts[&loan_location].clone(); @@ -2121,10 +2213,15 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { let borrow_infos = &contract.borrow_infos; match borrow_infos.len().cmp(&1) { std::cmp::Ordering::Less => (), - std::cmp::Ordering::Greater => return Err(SpannedEncodingError::internal( - format!("we require at most one magic wand in the postcondition. But we have {:?}", borrow_infos.len()), - span, - )), + std::cmp::Ordering::Greater => { + return Err(SpannedEncodingError::internal( + format!( + "we require at most one magic wand in the postcondition. But we have {:?}", + borrow_infos.len() + ), + span, + )) + } std::cmp::Ordering::Equal => { let borrow_info = &borrow_infos[0]; @@ -2142,9 +2239,9 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { // Obtain the LHS permission. for (path, _) in &borrow_info.blocking_paths { - let (encoded_place, _, _) = self.encode_generic_place( - contract.def_id, Some(loan_location), *path - ).with_span(span)?; + let (encoded_place, _, _) = self + .encode_generic_place(contract.def_id, Some(loan_location), *path) + .with_span(span)?; let encoded_place = replace_fake_exprs(encoded_place); // Move the permissions from the "in loans" ("reborrowing loans") to the current loan @@ -2179,15 +2276,13 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { ErrorCtxt::ApplyMagicWandOnExpiry, ); // Inhale the magic wand. - let magic_wand = vir::Expr::MagicWand( vir::MagicWand { + let magic_wand = vir::Expr::MagicWand(vir::MagicWand { left: Box::new(lhs.clone()), right: Box::new(rhs.clone()), borrow: Some(loan.index().into()), position: pos, }); - stmts.push(vir::Stmt::Inhale( vir::Inhale { - expr: magic_wand - })); + stmts.push(vir::Stmt::Inhale(vir::Inhale { expr: magic_wand })); // Emit the apply statement. let statement = vir::Stmt::apply_magic_wand(lhs, rhs, loan.index().into(), pos); debug!("{:?} at {:?}", statement, loan_location); @@ -2220,9 +2315,14 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { ) -> SpannedEncodingResult> { let mut stmts: Vec = vec![]; if !loans.is_empty() { - let vir_reborrowing_dag = - self.construct_vir_reborrowing_dag(&loans, zombie_loans, location, end_location, is_in_package_stmt)?; - stmts.push(vir::Stmt::ExpireBorrows( vir::ExpireBorrows { + let vir_reborrowing_dag = self.construct_vir_reborrowing_dag( + &loans, + zombie_loans, + location, + end_location, + is_in_package_stmt, + )?; + stmts.push(vir::Stmt::ExpireBorrows(vir::ExpireBorrows { dag: vir_reborrowing_dag, })); } @@ -2239,15 +2339,23 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { .polonius_info() .get_all_loans_dying_between(begin_loc, end_loc); // FIXME: is 'end_loc' correct here? What about 'begin_loc'? - self.encode_expiration_of_loans(all_dying_loans, &zombie_loans, begin_loc, Some(end_loc), false) + self.encode_expiration_of_loans( + all_dying_loans, + &zombie_loans, + begin_loc, + Some(end_loc), + false, + ) } #[tracing::instrument(level = "debug", skip(self))] - fn encode_expiring_borrows_at(&mut self, location: mir::Location) - -> SpannedEncodingResult> - { + fn encode_expiring_borrows_at( + &mut self, + location: mir::Location, + ) -> SpannedEncodingResult> { let (all_dying_loans, zombie_loans) = self.polonius_info().get_all_loans_dying_at(location); - let stmts = self.encode_expiration_of_loans(all_dying_loans, &zombie_loans, location, None, false)?; + let stmts = + self.encode_expiration_of_loans(all_dying_loans, &zombie_loans, location, None, false)?; Ok(self.set_stmts_default_pos(stmts, self.mir_encoder.get_span_of_location(location))) } @@ -2319,29 +2427,27 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { // Use a local variable for the discriminant. // See Silicon issue https://github.com/viperproject/silicon/issues/356 let discr_var = match switch_ty.kind() { - ty::TyKind::Bool => { - self.cfg_method.add_fresh_local_var(vir::Type::Bool) - } + ty::TyKind::Bool => self.cfg_method.add_fresh_local_var(vir::Type::Bool), - ty::TyKind::Int(_) - | ty::TyKind::Uint(_) - | ty::TyKind::Char => { + ty::TyKind::Int(_) | ty::TyKind::Uint(_) | ty::TyKind::Char => { self.cfg_method.add_fresh_local_var(vir::Type::Int) } - ty::TyKind::Float(ty::FloatTy::F32) => { - self.cfg_method.add_fresh_local_var(vir::Type::Float(Float::F32)) - } + ty::TyKind::Float(ty::FloatTy::F32) => self + .cfg_method + .add_fresh_local_var(vir::Type::Float(Float::F32)), - ty::TyKind::Float(ty::FloatTy::F64) => { - self.cfg_method.add_fresh_local_var(vir::Type::Float(Float::F64)) - } + ty::TyKind::Float(ty::FloatTy::F64) => self + .cfg_method + .add_fresh_local_var(vir::Type::Float(Float::F64)), ref x => unreachable!("{:?}", x), }; - let encoded_discr = self.mir_encoder.encode_operand_expr(discr) + let encoded_discr = self + .mir_encoder + .encode_operand_expr(discr) .with_span(span)?; - stmts.push(vir::Stmt::Assign( vir::Assign { + stmts.push(vir::Stmt::Assign(vir::Assign { target: discr_var.clone().into(), source: encoded_discr, kind: vir::AssignKind::Copy, @@ -2362,12 +2468,12 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { } } - ty::TyKind::Int(_) - | ty::TyKind::Uint(_) - | ty::TyKind::Char => vir::Expr::eq_cmp( - discr_var.clone().into(), - self.encoder.encode_int_cast(value, switch_ty), - ), + ty::TyKind::Int(_) | ty::TyKind::Uint(_) | ty::TyKind::Char => { + vir::Expr::eq_cmp( + discr_var.clone().into(), + self.encoder.encode_int_cast(value, switch_ty), + ) + } ref x => unreachable!("{:?}", x), }; @@ -2404,13 +2510,12 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { if guard_is_bool && cfg_targets.len() == 1 { let (target_guard, target) = cfg_targets.pop().unwrap(); let target_span = self.mir_encoder.get_span_of_basic_block(target); - let default_target_span = self.mir_encoder.get_span_of_basic_block(default_target); + let default_target_span = + self.mir_encoder.get_span_of_basic_block(default_target); if target_span > default_target_span { let guard_pos = target_guard.pos(); - cfg_targets = vec![( - target_guard.negate().set_pos(guard_pos), - default_target, - )]; + cfg_targets = + vec![(target_guard.negate().set_pos(guard_pos), default_target)]; default_target = target; } else { // Undo the pop @@ -2435,7 +2540,7 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { TerminatorKind::UnwindTerminate(..) => { let pos = self.register_error(term.source_info.span, ErrorCtxt::AbortTerminator); - stmts.push(vir::Stmt::Assert( vir::Assert { + stmts.push(vir::Stmt::Assert(vir::Assert { expr: false.into(), position: pos, })); @@ -2456,21 +2561,23 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { ref args, destination, target, - func: - mir::Operand::Constant(box mir::Constant { - literal, - .. - }), + func: mir::Operand::Constant(box mir::Constant { literal, .. }), .. } => { let ty = literal.ty(); let func_const_val = literal.try_to_scalar_int(); if let ty::TyKind::FnDef(called_def_id, call_substs) = ty.kind() { let called_def_id = *called_def_id; - debug!("Encode function call {:?} with substs {:?}", called_def_id, call_substs); + debug!( + "Encode function call {:?} with substs {:?}", + called_def_id, call_substs + ); - let full_func_proc_name: &str = - &self.encoder.env().name.get_absolute_item_name(called_def_id); + let full_func_proc_name: &str = &self + .encoder + .env() + .name + .get_absolute_item_name(called_def_id); match full_func_proc_name { "std::rt::begin_panic" @@ -2483,19 +2590,18 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { // Example of args[0]: 'const "internal error: entered unreachable code"' let panic_message = format!("{:?}", args[0]); - let panic_cause = self.mir_encoder.encode_panic_cause( - term.source_info.span - ); + let panic_cause = + self.mir_encoder.encode_panic_cause(term.source_info.span); let pos = self.register_error( - term.source_info.span, - ErrorCtxt::Panic(panic_cause), - ); + term.source_info.span, + ErrorCtxt::Panic(panic_cause), + ); if self.check_panics { stmts.push(vir::Stmt::comment(format!( "Rust panic - {panic_message}" ))); - stmts.push(vir::Stmt::Assert( vir::Assert { + stmts.push(vir::Stmt::Assert(vir::Assert { expr: false.into(), position: pos, })); @@ -2504,94 +2610,91 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { } } - "std::boxed::Box::::new" - | "alloc::boxed::Box::::new" => { + "std::boxed::Box::::new" | "alloc::boxed::Box::::new" => { // This is the initialization of a box // args[0]: value to put in the box assert_eq!(args.len(), 1); - let (dst, pre_stmts, dest_ty, _) = self.encode_place(destination, ArrayAccessKind::Shared, location)?; + let (dst, pre_stmts, dest_ty, _) = + self.encode_place(destination, ArrayAccessKind::Shared, location)?; stmts.extend(pre_stmts); let boxed_ty = dest_ty.boxed_ty(); - let ref_field = self.encoder.encode_dereference_field(boxed_ty) + let ref_field = self + .encoder + .encode_dereference_field(boxed_ty) .with_span(span)?; let box_content = dst.clone().field(ref_field.clone()); - stmts.extend( - self.prepare_assign_target( - dst, - ref_field, - location, - vir::AssignKind::Move, - false - )? - ); + stmts.extend(self.prepare_assign_target( + dst, + ref_field, + location, + vir::AssignKind::Move, + false, + )?); // Allocate `box_content` - stmts.extend(self.encode_havoc_and_initialization(&box_content).with_span(span)?); - - // Initialize `box_content` stmts.extend( - self.encode_assign_operand( - &box_content, - &args[0], - location - )? + self.encode_havoc_and_initialization(&box_content) + .with_span(span)?, ); - } - "std::cmp::PartialEq::eq" | - "core::cmp::PartialEq::eq" - if args.len() == 2 && - self.encoder.has_structural_eq_impl( - self.mir_encoder.get_operand_ty(&args[0]) - ) - => { - debug!("Encoding call of PartialEq::eq"); - stmts.extend( - self.encode_cmp_function_call( - called_def_id, - location, - term.source_info.span, - args, - destination, - target, - vir::BinaryOpKind::EqCmp, - call_substs, - )? - ); + // Initialize `box_content` + stmts.extend(self.encode_assign_operand( + &box_content, + &args[0], + location, + )?); } - "std::cmp::PartialEq::ne" | - "core::cmp::PartialEq::ne" - if args.len() == 2 && - self.encoder.has_structural_eq_impl( - self.mir_encoder.get_operand_ty(&args[0]) - ) - => { + "std::cmp::PartialEq::eq" | "core::cmp::PartialEq::eq" + if args.len() == 2 + && self.encoder.has_structural_eq_impl( + self.mir_encoder.get_operand_ty(&args[0]), + ) => + { + debug!("Encoding call of PartialEq::eq"); + stmts.extend(self.encode_cmp_function_call( + called_def_id, + location, + term.source_info.span, + args, + destination, + target, + vir::BinaryOpKind::EqCmp, + call_substs, + )?); + } + + "std::cmp::PartialEq::ne" | "core::cmp::PartialEq::ne" + if args.len() == 2 + && self.encoder.has_structural_eq_impl( + self.mir_encoder.get_operand_ty(&args[0]), + ) => + { debug!("Encoding call of PartialEq::ne"); - stmts.extend( - self.encode_cmp_function_call( - called_def_id, - location, - term.source_info.span, - args, - destination, - target, - vir::BinaryOpKind::NeCmp, - call_substs, - )? - ); + stmts.extend(self.encode_cmp_function_call( + called_def_id, + location, + term.source_info.span, + args, + destination, + target, + vir::BinaryOpKind::NeCmp, + call_substs, + )?); } - "std::ops::Fn::call" - | "core::ops::Fn::call" => { + "std::ops::Fn::call" | "core::ops::Fn::call" => { let cl_type: ty::Ty = call_substs[0].expect_ty(); match cl_type.kind() { ty::TyKind::Closure(cl_def_id, _) => { - debug!("Encoding call to closure {:?} with func {:?}", cl_def_id, func_const_val); + debug!( + "Encoding call to closure {:?} with func {:?}", + cl_def_id, func_const_val + ); stmts.extend(self.encode_impure_function_call( location, term.source_info.span, @@ -2613,18 +2716,15 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { } "core::slice::::len" => { - stmts.extend( - self.encode_slice_len_call( - destination, - args, - location, - span, - )? - ); + stmts.extend(self.encode_slice_len_call( + destination, + args, + location, + span, + )?); } - "std::iter::Iterator::next" | - "core::iter::Iterator::next" => { + "std::iter::Iterator::next" | "core::iter::Iterator::next" => { return Err(SpannedEncodingError::unsupported( "iterators are not fully supported yet", term.source_info.span, @@ -2632,23 +2732,22 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { } // TODO: use extern_spec - "core::ops::IndexMut::index_mut" | - "std::ops::IndexMut::index_mut" => { + "core::ops::IndexMut::index_mut" | "std::ops::IndexMut::index_mut" => { return Err(SpannedEncodingError::unsupported( "mutably slicing is not fully supported yet", term.source_info.span, )); } - "core::ops::Index::index" | - "std::ops::Index::index" => { + "core::ops::Index::index" | "std::ops::Index::index" => { stmts.extend( self.encode_sequence_index_call( destination, args, location, term.source_info.span, - ).with_span(span)? + ) + .with_span(span)?, ); } @@ -2656,7 +2755,10 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { // The called method might be a trait method. // We try to resolve it to the concrete implementation // and type substitutions. - let (called_def_id, call_substs) = self.encoder.env().query + let (called_def_id, call_substs) = self + .encoder + .env() + .query .resolve_method_call(self.proc_def_id, called_def_id, call_substs); let is_pure_function = self.encoder.is_pure(called_def_id, Some(call_substs)) && @@ -2666,7 +2768,8 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { self.proc_def_id != called_def_id; if is_pure_function { let def_id = called_def_id; - let (function_name, _) = self.encoder + let (function_name, _) = self + .encoder .encode_pure_function_use(def_id, self.proc_def_id, call_substs) .with_default_span(term.source_info.span)?; debug!("Encoding pure function call '{}'", function_name); @@ -2676,29 +2779,25 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { let _ = self.mir_encoder.encode_operand_expr(operand); } - stmts.extend( - self.encode_pure_function_call( - location, - term.source_info.span, - args, - destination, - target, - def_id, - call_substs, - )? - ); + stmts.extend(self.encode_pure_function_call( + location, + term.source_info.span, + args, + destination, + target, + def_id, + call_substs, + )?); } else { - stmts.extend( - self.encode_impure_function_call( - location, - term.source_info.span, - args, - destination, - target, - called_def_id, - call_substs, - )? - ); + stmts.extend(self.encode_impure_function_call( + location, + term.source_info.span, + args, + destination, + target, + called_def_id, + call_substs, + )?); } } } @@ -2735,12 +2834,12 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { // Use local variables in the switch/if. // See Silicon issue https://github.com/viperproject/silicon/issues/356 let cond_var = self.cfg_method.add_fresh_local_var(vir::Type::Bool); - stmts.push(vir::Stmt::Assign( vir::Assign { + stmts.push(vir::Stmt::Assign(vir::Assign { target: cond_var.clone().into(), - source: self.mir_encoder.encode_operand_expr(cond) - .with_span( - self.mir_encoder.get_span_of_location(location) - )?, + source: self + .mir_encoder + .encode_operand_expr(cond) + .with_span(self.mir_encoder.get_span_of_location(location))?, kind: vir::AssignKind::Copy, })); @@ -2751,7 +2850,8 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { }; // Check or assume the assertion - let (assert_msg, error_ctxt) = if let box mir::AssertKind::BoundsCheck { .. } = msg { + let (assert_msg, error_ctxt) = if let box mir::AssertKind::BoundsCheck { .. } = msg + { let mut s = String::new(); msg.fmt_assert_args(&mut s).unwrap(); (s, ErrorCtxt::BoundsCheckAssert) @@ -2762,18 +2862,13 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { stmts.push(vir::Stmt::comment(format!("Rust assertion: {assert_msg}"))); if self.check_panics { - stmts.push(vir::Stmt::Assert( vir::Assert { + stmts.push(vir::Stmt::Assert(vir::Assert { expr: viper_guard, - position: self.register_error( - term.source_info.span, - error_ctxt, - ), + position: self.register_error(term.source_info.span, error_ctxt), })); } else { stmts.push(vir::Stmt::comment("This assertion will not be checked")); - stmts.push(vir::Stmt::Inhale( vir::Inhale { - expr: viper_guard, - })); + stmts.push(vir::Stmt::Inhale(vir::Inhale { expr: viper_guard })); }; (stmts, MirSuccessor::Goto(target)) @@ -2796,7 +2891,9 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { span: Span, ) -> SpannedEncodingResult> { assert!(args.len() == 1, "unexpected args to slice::len(): {args:?}"); - let slice_operand = self.mir_encoder.encode_operand_expr(&args[0]) + let slice_operand = self + .mir_encoder + .encode_operand_expr(&args[0]) .with_span(span)?; let mut stmts = vec![]; @@ -2806,28 +2903,30 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { stmts.push(vir::Stmt::label(label.clone())); let slice_ty_ref = self.mir_encoder.get_operand_ty(&args[0]); - let slice_ty = if let ty::TyKind::Ref(_, slice_ty, _) = slice_ty_ref.kind() { slice_ty } else { unreachable!() }; - let slice_types = self.encoder.encode_sequence_types(*slice_ty).with_span(span)?; + let slice_ty = if let ty::TyKind::Ref(_, slice_ty, _) = slice_ty_ref.kind() { + slice_ty + } else { + unreachable!() + }; + let slice_types = self + .encoder + .encode_sequence_types(*slice_ty) + .with_span(span)?; let rhs = slice_types.len(self.encoder, slice_operand); - let (encoded_lhs, encode_stmts, ty, _) = self.encode_place( - destination, - ArrayAccessKind::Mutable(None, location), - location - ).with_span(span)?; + let (encoded_lhs, encode_stmts, ty, _) = self + .encode_place( + destination, + ArrayAccessKind::Mutable(None, location), + location, + ) + .with_span(span)?; stmts.extend(encode_stmts); - stmts.extend( - self.encode_copy_value_assign( - encoded_lhs, - rhs, - ty, - location, - )? - ); + stmts.extend(self.encode_copy_value_assign(encoded_lhs, rhs, ty, location)?); - self.encode_transfer_args_permissions(location, args, &mut stmts, &label, false)?; + self.encode_transfer_args_permissions(location, args, &mut stmts, &label, false)?; // Store a label for permissions got back from the call debug!( @@ -2845,12 +2944,15 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { destination: mir::Place<'tcx>, args: &[mir::Operand<'tcx>], location: mir::Location, - error_span: Span + error_span: Span, ) -> EncodingResult> { // args[0] is the base array/slice, args[1] is the index // index is not specified exactly, as std::ops::Index::index is a trait method, so all we // know is there needs to be an impl Index for T - assert!(args.len() == 2, "unexpected args to sequence index call: {args:?}"); + assert!( + args.len() == 2, + "unexpected args to sequence index call: {args:?}" + ); let mut stmts = vec![]; @@ -2868,7 +2970,11 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { if !lhs_ty.is_slice_or_ref() && !lhs_ty.is_array_or_ref() { error_unsupported!("Non-slice LHS type '{:?}' not supported yet", lhs_ty); } - let mutability = if let ty::TyKind::Ref(_, _, mutability) = lhs_ty.kind() { mutability } else { unreachable!() }; + let mutability = if let ty::TyKind::Ref(_, _, mutability) = lhs_ty.kind() { + mutability + } else { + unreachable!() + }; let perm_amount = match mutability { Mutability::Mut => vir::PermAmount::Write, Mutability::Not => vir::PermAmount::Read, @@ -2878,23 +2984,32 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { stmts.push(vir_stmt!{ inhale [vir::Expr::pred_permission(encoded_lhs.clone(), perm_amount).unwrap()] }); let lhs_slice_ty = lhs_ty.peel_refs(); - let lhs_slice_expr = self.encoder.encode_value_expr(encoded_lhs.clone(), lhs_ty)?; + let lhs_slice_expr = self + .encoder + .encode_value_expr(encoded_lhs.clone(), lhs_ty)?; let base_seq = self.mir_encoder.encode_operand_place(&args[0])?.unwrap(); let base_seq_ty = self.mir_encoder.get_operand_ty(&args[0]); if !base_seq_ty.is_slice_or_ref() && !base_seq_ty.is_array_or_ref() { - error_unsupported!("Slicing is only supported for arrays/slices currently, not '{:?}'", base_seq_ty); + error_unsupported!( + "Slicing is only supported for arrays/slices currently, not '{:?}'", + base_seq_ty + ); } // base_seq is expected to be ref$Array$.. or ref$Slice$.., but lookup_pure wants the // contained Array$../Slice$.. let base_seq_expr = self.encoder.encode_value_expr(base_seq, base_seq_ty)?; - let enc_sequence_types = self.encoder.encode_sequence_types(base_seq_ty.peel_refs())?; + let enc_sequence_types = self + .encoder + .encode_sequence_types(base_seq_ty.peel_refs())?; - let j = vir_local!{ j: Int }; - let elem_snap_ty = self.encoder.encode_snapshot_type(enc_sequence_types.elem_ty_rs)?; + let j = vir_local! { j: Int }; + let elem_snap_ty = self + .encoder + .encode_snapshot_type(enc_sequence_types.elem_ty_rs)?; let rhs_lookup_j = enc_sequence_types.encode_lookup_pure_call( self.encoder, base_seq_expr.clone(), @@ -2905,7 +3020,11 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { let encoded_idx = self.mir_encoder.encode_operand_place(&args[1])?.unwrap(); trace!("idx: {:?}", encoded_idx); let idx_ty = self.mir_encoder.get_operand_ty(&args[1]); - let idx_ident = self.encoder.env().name.get_absolute_item_name(idx_ty.ty_adt_def().unwrap().did()); + let idx_ident = self + .encoder + .env() + .name + .get_absolute_item_name(idx_ty.ty_adt_def().unwrap().did()); trace!("ident: {}", idx_ident); self.slice_created_at.insert(location, encoded_lhs); @@ -2915,16 +3034,32 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { // TODO: there's fields like _5.f$start.val_int on `encoded_idx`, it just feels hacky to // manually re-do and hardcode them here when we probably just encoded the type // and the construction of the fields. - let usize_ty = self.encoder.env().tcx().mk_ty_from_kind(ty::TyKind::Uint(ty::UintTy::Usize)); + let usize_ty = self + .encoder + .env() + .tcx() + .mk_ty_from_kind(ty::TyKind::Uint(ty::UintTy::Usize)); let start = match &*idx_ident { - "std::ops::Range" | "core::ops::Range" | - "std::ops::RangeFrom" | "core::ops::RangeFrom" => { - let start_expr = self.encoder.encode_struct_field_value(encoded_idx.clone(), "start", usize_ty)?; + "std::ops::Range" + | "core::ops::Range" + | "std::ops::RangeFrom" + | "core::ops::RangeFrom" => { + let start_expr = self.encoder.encode_struct_field_value( + encoded_idx.clone(), + "start", + usize_ty, + )?; if self.check_panics { // Check indexing in bounds - stmts.push(vir::Stmt::Assert( vir::Assert { - expr: vir_expr!{ [start_expr] >= [vir::Expr::from(0usize)] }, - position: self.register_error(error_span, ErrorCtxt::SliceRangeBoundsCheckAssert("the range start value may be smaller than 0 when slicing".to_string())), + stmts.push(vir::Stmt::Assert(vir::Assert { + expr: vir_expr! { [start_expr] >= [vir::Expr::from(0usize)] }, + position: self.register_error( + error_span, + ErrorCtxt::SliceRangeBoundsCheckAssert( + "the range start value may be smaller than 0 when slicing" + .to_string(), + ), + ), })); } start_expr @@ -2932,71 +3067,102 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { // RangeInclusive is wierdly differnet to all of the other Range*s in that the struct fields are private // and it is created with a new() fn and start/end are accessed with getter fns // See https://github.com/rust-lang/rust/issues/67371 for why this is the case... - "std::ops::RangeInclusive" | "core::ops::RangeInclusive" => return Err( - EncodingError::unsupported("slicing with RangeInclusive (e.g. [x..=y]) currently not supported".to_string()) - ), - "std::ops::RangeTo" | "core::ops::RangeTo" | - "std::ops::RangeFull" | "core::ops::RangeFull" | - "std::ops::RangeToInclusive" | "core::ops::RangeToInclusive" => vir::Expr::from(0usize), - _ => unreachable!("{}", idx_ident) + "std::ops::RangeInclusive" | "core::ops::RangeInclusive" => { + return Err(EncodingError::unsupported( + "slicing with RangeInclusive (e.g. [x..=y]) currently not supported" + .to_string(), + )) + } + "std::ops::RangeTo" + | "core::ops::RangeTo" + | "std::ops::RangeFull" + | "core::ops::RangeFull" + | "std::ops::RangeToInclusive" + | "core::ops::RangeToInclusive" => vir::Expr::from(0usize), + _ => unreachable!("{}", idx_ident), }; let end = match &*idx_ident { - "std::ops::Range" | "core::ops::Range" | - "std::ops::RangeTo" | "core::ops::RangeTo" => { - let end_expr = self.encoder.encode_struct_field_value(encoded_idx, "end", usize_ty)?; + "std::ops::Range" | "core::ops::Range" | "std::ops::RangeTo" | "core::ops::RangeTo" => { + let end_expr = + self.encoder + .encode_struct_field_value(encoded_idx, "end", usize_ty)?; if self.check_panics { // Check indexing in bounds - stmts.push(vir::Stmt::Assert( vir::Assert { - expr: vir_expr!{ [end_expr] <= [original_len] }, - position: self.register_error(error_span, ErrorCtxt::SliceRangeBoundsCheckAssert("the range end value may be out of bounds when slicing".to_string())), + stmts.push(vir::Stmt::Assert(vir::Assert { + expr: vir_expr! { [end_expr] <= [original_len] }, + position: self.register_error( + error_span, + ErrorCtxt::SliceRangeBoundsCheckAssert( + "the range end value may be out of bounds when slicing".to_string(), + ), + ), })); } end_expr } - "std::ops::RangeInclusive" | "core::ops::RangeInclusive" => return Err( - EncodingError::unsupported("slicing with RangeInclusive (e.g. [x..=y]) currently not supported".to_string()) - ), + "std::ops::RangeInclusive" | "core::ops::RangeInclusive" => { + return Err(EncodingError::unsupported( + "slicing with RangeInclusive (e.g. [x..=y]) currently not supported" + .to_string(), + )) + } "std::ops::RangeToInclusive" | "core::ops::RangeToInclusive" => { - let end_expr = self.encoder.encode_struct_field_value(encoded_idx, "end", usize_ty)?; - let end_expr = vir_expr!{ [end_expr] + [vir::Expr::from(1usize)] }; + let end_expr = + self.encoder + .encode_struct_field_value(encoded_idx, "end", usize_ty)?; + let end_expr = vir_expr! { [end_expr] + [vir::Expr::from(1usize)] }; if self.check_panics { // Check indexing in bounds - stmts.push(vir::Stmt::Assert( vir::Assert { - expr: vir_expr!{ [end_expr] <= [original_len] }, - position: self.register_error(error_span, ErrorCtxt::SliceRangeBoundsCheckAssert("the range end value may be out of bounds when slicing".to_string())), + stmts.push(vir::Stmt::Assert(vir::Assert { + expr: vir_expr! { [end_expr] <= [original_len] }, + position: self.register_error( + error_span, + ErrorCtxt::SliceRangeBoundsCheckAssert( + "the range end value may be out of bounds when slicing".to_string(), + ), + ), })); } end_expr } - "std::ops::RangeFrom" | "core::ops::RangeFrom" | - "std::ops::RangeFull" | "core::ops::RangeFull" => original_len, - _ => unreachable!("{}", idx_ident) + "std::ops::RangeFrom" + | "core::ops::RangeFrom" + | "std::ops::RangeFull" + | "core::ops::RangeFull" => original_len, + _ => unreachable!("{}", idx_ident), }; trace!("start: {}, end: {}", start, end); let slice_types_lhs = self.encoder.encode_sequence_types(lhs_slice_ty)?; - let elem_snap_ty = self.encoder.encode_snapshot_type(slice_types_lhs.elem_ty_rs)?; + let elem_snap_ty = self + .encoder + .encode_snapshot_type(slice_types_lhs.elem_ty_rs)?; // length - let length = vir_expr!{ [end] - [start] }; + let length = vir_expr! { [end] - [start] }; if self.check_panics { // start must be leq than end if idx_ident != "std::ops::RangeFull" && idx_ident != "core::ops::RangeFull" { - stmts.push(vir::Stmt::Assert( vir::Assert { - expr: vir_expr!{ [start] <= [end] }, - position: self.register_error(error_span, ErrorCtxt::SliceRangeBoundsCheckAssert("the range end may be smaller than the start when slicing".to_string())), + stmts.push(vir::Stmt::Assert(vir::Assert { + expr: vir_expr! { [start] <= [end] }, + position: self.register_error( + error_span, + ErrorCtxt::SliceRangeBoundsCheckAssert( + "the range end may be smaller than the start when slicing".to_string(), + ), + ), })); } } let slice_len_call = slice_types_lhs.len(self.encoder, lhs_slice_expr.clone()); - stmts.push(vir_stmt!{ + stmts.push(vir_stmt! { inhale [vir_expr!{ [slice_len_call] == [length] }] }); // lookup_pure: contents - let i = vir_local!{ i: Int }; + let i = vir_local! { i: Int }; let i_var: vir::Expr = i.clone().into(); let j_var: vir::Expr = j.clone().into(); @@ -3012,8 +3178,8 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { // NOTE: the lhs_ and rhs_ here refer to the moment the slice is created, so lhs_lookup is // lookup on the slice currently being created, and rhs_lookup is on the array or slice // being sliced - let lookup_eq = vir_expr!{ [lhs_lookup_i] == [rhs_lookup_j] }; - let indices = vir_expr!{ + let lookup_eq = vir_expr! { [lhs_lookup_i] == [rhs_lookup_j] }; + let indices = vir_expr! { [vir_expr!{ [vir::Expr::from(0usize)] <= [i_var] }] && ( [vir_expr!{ [i_var] < [slice_len_call] }] && @@ -3028,7 +3194,7 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { }; // forall i: Int, j: Int :: { lhs_lookup(i), rhs_lookup(j) } 0 <= i && i < slice$len && j == i + start && start <= j && j < end ==> lhs_lookup(i) == rhs_lookup(j) - stmts.push(vir_stmt!{ + stmts.push(vir_stmt! { inhale [ vir::Expr::forall( vec![i, j], @@ -3038,7 +3204,7 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { ] }); - self.encode_transfer_args_permissions(location, args, &mut stmts, &label, false)?; + self.encode_transfer_args_permissions(location, args, &mut stmts, &label, false)?; // Store a label for permissions got back from the call debug!( "Pure function call location {:?} has label {}", @@ -3069,37 +3235,40 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { ) -> SpannedEncodingResult> { let arg_ty = self.mir_encoder.get_operand_ty(&args[0]); - if self.encoder.supports_snapshot_equality(arg_ty).with_span(call_site_span)? { - let lhs = self.mir_encoder.encode_operand_expr(&args[0]) + if self + .encoder + .supports_snapshot_equality(arg_ty) + .with_span(call_site_span)? + { + let lhs = self + .mir_encoder + .encode_operand_expr(&args[0]) .with_span(call_site_span)?; - let rhs = self.mir_encoder.encode_operand_expr(&args[1]) + let rhs = self + .mir_encoder + .encode_operand_expr(&args[1]) .with_span(call_site_span)?; let expr = match bin_op { - vir::BinaryOpKind::EqCmp => vir::Expr::eq_cmp( - vir::Expr::snap_app(lhs), - vir::Expr::snap_app(rhs), - ), - vir::BinaryOpKind::NeCmp => vir::Expr::ne_cmp( - vir::Expr::snap_app(lhs), - vir::Expr::snap_app(rhs), - ), - _ => unreachable!() + vir::BinaryOpKind::EqCmp => { + vir::Expr::eq_cmp(vir::Expr::snap_app(lhs), vir::Expr::snap_app(rhs)) + } + vir::BinaryOpKind::NeCmp => { + vir::Expr::ne_cmp(vir::Expr::snap_app(lhs), vir::Expr::snap_app(rhs)) + } + _ => unreachable!(), }; - let (target_value, mut stmts) = self.encode_pure_function_call_lhs_value(destination, target, location) + let (target_value, mut stmts) = self + .encode_pure_function_call_lhs_value(destination, target, location) .with_span(call_site_span)?; let inhaled_expr = vir::Expr::eq_cmp(target_value, expr); - let (call_stmts, label) = self.encode_pure_function_call_site( - location, - destination, - target, - inhaled_expr, - )?; + let (call_stmts, label) = + self.encode_pure_function_call_site(location, destination, target, inhaled_expr)?; stmts.extend(call_stmts); - self.encode_transfer_args_permissions(location, args, &mut stmts, &label, false)?; + self.encode_transfer_args_permissions(location, args, &mut stmts, &label, false)?; Ok(stmts) } else { @@ -3171,7 +3340,10 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { .env() .name .get_absolute_item_name(called_def_id); - debug!("Encoding non-pure function call '{}' with args {:?} and substs {:?}", full_func_proc_name, mir_args, substs); + debug!( + "Encoding non-pure function call '{}' with args {:?} and substs {:?}", + full_func_proc_name, mir_args, substs + ); // Spans for fake exprs that cannot be encoded in viper let mut fake_expr_spans: FxHashMap = FxHashMap::default(); @@ -3183,8 +3355,10 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { // - the VIR Local that will hold hold the argument before the call // - the type of the argument // - if not constant, the VIR expression for the argument - let mut operands: Vec<(&mir::Operand<'tcx>, Local, ty::Ty<'tcx>, Option)> = vec![]; - let mut encoded_operands = mir_args.iter() + let mut operands: Vec<(&mir::Operand<'tcx>, Local, ty::Ty<'tcx>, Option)> = + vec![]; + let mut encoded_operands = mir_args + .iter() .map(|arg| self.mir_encoder.encode_operand_place(arg)) .collect::>, _>>() .with_span(call_site_span)?; @@ -3196,12 +3370,10 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { let cl_ty = self.mir_encoder.get_operand_ty(&mir_args[0]); operands.push(( &mir_args[0], - mir_args[0].place() + mir_args[0] + .place() .and_then(|place| place.as_local()) - .map_or_else( - || self.locals.get_fresh(cl_ty), - |local| local.into() - ), + .map_or_else(|| self.locals.get_fresh(cl_ty), |local| local.into()), cl_ty, encoded_operands[0].take(), )); @@ -3228,7 +3400,11 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { // TODO: weird fix for closure call substitutions, we need to // prepend the identity substs of the containing method ... - substs = self.encoder.env().tcx().mk_args_from_iter(self.substs.iter().chain(substs)); + substs = self + .encoder + .env() + .tcx() + .mk_args_from_iter(self.substs.iter().chain(substs)); } else { for (arg, encoded_operand) in mir_args.iter().zip(encoded_operands.iter_mut()) { let arg_ty = self.mir_encoder.get_operand_ty(arg); @@ -3236,10 +3412,7 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { arg, arg.place() .and_then(|place| place.as_local()) - .map_or_else( - || self.locals.get_fresh(arg_ty), - |local| local.into() - ), + .map_or_else(|| self.locals.get_fresh(arg_ty), |local| local.into()), arg_ty, encoded_operand.take(), )); @@ -3275,10 +3448,12 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { debug!("arg: {} {}", arg_place, place); if !self.encoder.is_pure(called_def_id, Some(substs)) { type_invs.push( - self.encoder.encode_invariant_func_app( - arg_ty, - vir::Expr::snap_app(place.clone()), - ).with_span(call_site_span)?, + self.encoder + .encode_invariant_func_app( + arg_ty, + vir::Expr::snap_app(place.clone()), + ) + .with_span(call_site_span)?, ); } fake_exprs.insert(arg_place, place); @@ -3288,28 +3463,28 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { // We have a constant. constant_args.push(arg_place.clone()); - let val_field = self.encoder.encode_value_field(arg_ty).with_span(call_site_span)?; + let val_field = self + .encoder + .encode_value_field(arg_ty) + .with_span(call_site_span)?; // TODO: String constants are not being encoded currently, // instead just inhale the permission to the value. if !is_str(arg_ty) { - let arg_val_expr = self.mir_encoder.encode_operand_expr(mir_arg) + let arg_val_expr = self + .mir_encoder + .encode_operand_expr(mir_arg) .with_span(call_site_span)?; debug!("arg_val_expr: {} {}", arg_place, arg_val_expr); fake_exprs.insert(arg_place.clone().field(val_field), arg_val_expr); } else { - fake_expr_spans.insert( - arg, - call_site_span - ); - stmts.push(vir::Stmt::Inhale ( - vir::Inhale { - expr: vir::Expr::acc_permission( - arg_place.clone().field(val_field), - vir::PermAmount::Read - ) - } - )); + fake_expr_spans.insert(arg, call_site_span); + stmts.push(vir::Stmt::Inhale(vir::Inhale { + expr: vir::Expr::acc_permission( + arg_place.clone().field(val_field), + vir::PermAmount::Read, + ), + })); } let in_loop = self.loop_encoder.get_loop_depth(location.block) > 0; if in_loop { @@ -3328,7 +3503,8 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { let (target_local, encoded_target) = { if target.is_some() { - let (encoded_target, pre_stmts, ty, _) = self.encode_place(destination, ArrayAccessKind::Shared, location)?; + let (encoded_target, pre_stmts, ty, _) = + self.encode_place(destination, ArrayAccessKind::Shared, location)?; stmts.extend(pre_stmts); let target_local = if let Some(target_local) = destination.as_local() { @@ -3345,9 +3521,7 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { // The return type is Never // This means that the function call never returns // So, we `assume false` after the function call - stmts_after.push(vir::Stmt::Inhale( vir::Inhale { - expr: false.into() - })); + stmts_after.push(vir::Stmt::Inhale(vir::Inhale { expr: false.into() })); // Return a dummy local variable let never_ty = self.encoder.env().tcx().mk_ty_from_kind(ty::TyKind::Never); (self.locals.get_fresh(never_ty), None) @@ -3375,7 +3549,9 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { } } */ - vir::Expr::PredicateAccessPredicate( vir::PredicateAccessPredicate {ref argument, ..} ) => { + vir::Expr::PredicateAccessPredicate( + vir::PredicateAccessPredicate { ref argument, .. }, + ) => { if argument.is_local() && const_arg_vars.contains(argument) { // Skip predicate permission true.into() @@ -3393,13 +3569,15 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { }; let procedure_contract = { - self.encoder.get_procedure_contract_for_call( - self.proc_def_id, - called_def_id, - &arguments, - target_local, - substs, - ).with_span(call_site_span)? + self.encoder + .get_procedure_contract_for_call( + self.proc_def_id, + called_def_id, + &arguments, + target_local, + substs, + ) + .with_span(call_site_span)? }; assert_one_magic_wand(procedure_contract.borrow_infos.len()).with_span(call_site_span)?; @@ -3409,28 +3587,27 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { // Havoc and inhale variables that store constants for constant_arg in &constant_args { - stmts.extend(self.encode_havoc_and_initialization(constant_arg).with_span(call_site_span)?); + stmts.extend( + self.encode_havoc_and_initialization(constant_arg) + .with_span(call_site_span)?, + ); } // Encode precondition. - let ( - pre_type_spec, - pre_mandatory_type_spec, - pre_invs_spec, - pre_func_spec, - ) = self.encode_precondition_expr(&procedure_contract, substs, fake_expr_spans)?; + let (pre_type_spec, pre_mandatory_type_spec, pre_invs_spec, pre_func_spec) = + self.encode_precondition_expr(&procedure_contract, substs, fake_expr_spans)?; let pos = self.register_error(call_site_span, ErrorCtxt::ExhaleMethodPrecondition); - stmts.push(vir::Stmt::Assert( vir::Assert { + stmts.push(vir::Stmt::Assert(vir::Assert { expr: replace_fake_exprs(pre_func_spec), position: pos, })); - stmts.push(vir::Stmt::Assert( vir::Assert { + stmts.push(vir::Stmt::Assert(vir::Assert { expr: replace_fake_exprs(pre_invs_spec), position: pos, })); let pre_perm_spec = replace_fake_exprs(pre_type_spec); assert!(!pos.is_default()); - stmts.push(vir::Stmt::Exhale( vir::Exhale { + stmts.push(vir::Stmt::Exhale(vir::Exhale { expr: pre_perm_spec.remove_read_permissions(), position: pos, })); @@ -3448,10 +3625,10 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { let from_place = perm.get_place().unwrap().clone(); let to_place = from_place.clone().old(pre_label.clone()); let old_perm = perm.replace_place(&from_place, &to_place); - stmts.push(vir::Stmt::TransferPerm( vir::TransferPerm { + stmts.push(vir::Stmt::TransferPerm(vir::TransferPerm { left: from_place, right: to_place, - unchecked: true + unchecked: true, })); pre_mandatory_perms_old.push(old_perm); } @@ -3502,31 +3679,31 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { .collect(); let post_perm_spec = replace_fake_exprs(post_type_spec); - stmts.push(vir::Stmt::Inhale( vir::Inhale { + stmts.push(vir::Stmt::Inhale(vir::Inhale { expr: post_perm_spec.remove_read_permissions(), })); if let Some(access) = return_type_spec { - stmts.push(vir::Stmt::Inhale( vir::Inhale { + stmts.push(vir::Stmt::Inhale(vir::Inhale { expr: replace_fake_exprs(access), })); } for (from_place, to_place) in read_transfer { - stmts.push(vir::Stmt::TransferPerm( vir::TransferPerm { + stmts.push(vir::Stmt::TransferPerm(vir::TransferPerm { left: replace_fake_exprs(from_place), right: replace_fake_exprs(to_place), unchecked: true, })); } - stmts.push(vir::Stmt::Inhale( vir::Inhale { + stmts.push(vir::Stmt::Inhale(vir::Inhale { expr: replace_fake_exprs(post_invs_spec), })); - stmts.push(vir::Stmt::Inhale( vir::Inhale { + stmts.push(vir::Stmt::Inhale(vir::Inhale { expr: replace_fake_exprs(post_func_spec), })); // Exhale the permissions that were moved into magic wands. assert!(!pos.is_default()); - stmts.push(vir::Stmt::Exhale( vir::Exhale { + stmts.push(vir::Stmt::Exhale(vir::Exhale { expr: pre_mandatory_perm_spec, position: pos, })); @@ -3554,14 +3731,18 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { called_def_id: ProcedureDefId, call_substs: GenericArgsRef<'tcx>, ) -> SpannedEncodingResult> { - let (function_name, return_type) = self.encoder.encode_pure_function_use(called_def_id, self.proc_def_id, call_substs) + let (function_name, return_type) = self + .encoder + .encode_pure_function_use(called_def_id, self.proc_def_id, call_substs) .with_span(call_site_span)?; debug!("Encoding pure function call '{}'", function_name); assert!(target.is_some()); let mut arg_exprs = vec![]; for operand in args.iter() { - let arg_expr = self.mir_encoder.encode_operand_expr(operand) + let arg_expr = self + .mir_encoder + .encode_operand_expr(operand) .with_span(call_site_span)?; arg_exprs.push(arg_expr); } @@ -3598,7 +3779,8 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { .iter() .enumerate() .map(|(i, arg)| { - self.mir_encoder.encode_operand_expr_type(arg) + self.mir_encoder + .encode_operand_expr_type(arg) .map(|ty| vir::LocalVar::new(format!("x{i}"), ty)) }) .collect::>() @@ -3606,7 +3788,10 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { let pos = self.register_error(call_site_span, ErrorCtxt::PureFunctionCall); - let type_arguments = self.encoder.encode_generic_arguments(called_def_id, call_substs).with_span(call_site_span)?; + let type_arguments = self + .encoder + .encode_generic_arguments(called_def_id, call_substs) + .with_span(call_site_span)?; let func_call = vir::Expr::func_app( function_name, @@ -3614,32 +3799,27 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { arg_exprs, formal_args, return_type.clone(), - pos + pos, ); - let (target_value, mut stmts) = self.encode_pure_function_call_lhs_value(destination, target, location) + let (target_value, mut stmts) = self + .encode_pure_function_call_lhs_value(destination, target, location) .with_span(call_site_span)?; let inhaled_expr = if return_type.is_domain() || return_type.is_snapshot() { - let (target_place, pre_stmts) = self.encode_pure_function_call_lhs_place(destination, target, location)?; + let (target_place, pre_stmts) = + self.encode_pure_function_call_lhs_place(destination, target, location)?; stmts.extend(pre_stmts); - vir::Expr::eq_cmp( - vir::Expr::snap_app(target_place), - func_call, - ) + vir::Expr::eq_cmp(vir::Expr::snap_app(target_place), func_call) } else { vir::Expr::eq_cmp(target_value, func_call) }; - let (call_stmts, label) = self.encode_pure_function_call_site( - location, - destination, - target, - inhaled_expr - )?; + let (call_stmts, label) = + self.encode_pure_function_call_site(location, destination, target, inhaled_expr)?; stmts.extend(call_stmts); - self.encode_transfer_args_permissions(location, args, &mut stmts, &label, false)?; + self.encode_transfer_args_permissions(location, args, &mut stmts, &label, false)?; Ok(stmts) } @@ -3651,8 +3831,12 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { ) -> SpannedEncodingResult<(vir::Expr, Vec)> { let span = self.mir_encoder.get_span_of_location(location); assert!(target.is_some()); - let (encoded_place, pre_stmts, ty, _) = self.encode_place(destination, ArrayAccessKind::Shared, location)?; - let encoded_lhs_value = self.encoder.encode_value_expr(encoded_place, ty).with_span(span)?; + let (encoded_place, pre_stmts, ty, _) = + self.encode_place(destination, ArrayAccessKind::Shared, location)?; + let encoded_lhs_value = self + .encoder + .encode_value_expr(encoded_place, ty) + .with_span(span)?; Ok((encoded_lhs_value, pre_stmts)) } @@ -3663,7 +3847,8 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { location: mir::Location, ) -> SpannedEncodingResult<(vir::Expr, Vec)> { assert!(target.is_some()); - let (encoded, pre_stmts, _, _) = self.encode_place(destination, ArrayAccessKind::Shared, location)?; + let (encoded, pre_stmts, _, _) = + self.encode_place(destination, ArrayAccessKind::Shared, location)?; Ok((encoded, pre_stmts)) } @@ -3682,7 +3867,8 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { stmts.push(vir::Stmt::label(label.clone())); // Havoc the content of the lhs - let (target_place, pre_stmts) = self.encode_pure_function_call_lhs_place(destination, target, location)?; + let (target_place, pre_stmts) = + self.encode_pure_function_call_lhs_place(destination, target, location)?; stmts.extend(pre_stmts); stmts.extend(self.encode_havoc(&target_place).with_span(span)?); let type_predicate = self @@ -3690,16 +3876,12 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { .encode_place_predicate_permission(target_place.clone(), vir::PermAmount::Write) .unwrap(); - stmts.push(vir::Stmt::Inhale( vir::Inhale { + stmts.push(vir::Stmt::Inhale(vir::Inhale { expr: type_predicate, })); // Initialize the lhs - stmts.push( - vir::Stmt::Inhale( vir::Inhale { - expr: call_result, - }) - ); + stmts.push(vir::Stmt::Inhale(vir::Inhale { expr: call_result })); // Store a label for permissions got back from the call debug!( @@ -3723,17 +3905,15 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { let span = self.mir_encoder.get_span_of_location(location); for operand in args.iter() { let operand_ty = self.mir_encoder.get_operand_ty(operand); - let operand_place = self.mir_encoder.encode_operand_place(operand) + let operand_place = self + .mir_encoder + .encode_operand_place(operand) .with_span(span)?; match (operand_place, &operand_ty.kind()) { - ( - Some(ref place), - ty::TyKind::RawPtr(ty::TypeAndMut { - ty: inner_ty, .. - }), - ) + (Some(ref place), ty::TyKind::RawPtr(ty::TypeAndMut { ty: inner_ty, .. })) | (Some(ref place), ty::TyKind::Ref(_, inner_ty, _)) => { - let ref_field = self.encoder + let ref_field = self + .encoder .encode_dereference_field(*inner_ty) .with_span(span)?; let ref_place = place.clone().field(ref_field); @@ -3779,9 +3959,11 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { /// Encode permissions that are implicitly carried by the given local variable. /// `override_span` is used for local vars for fake expressions - fn encode_local_variable_permission(&self, local: Local, override_span: Option) - -> SpannedEncodingResult - { + fn encode_local_variable_permission( + &self, + local: Local, + override_span: Option, + ) -> SpannedEncodingResult { Ok(match self.locals.get_type(local).kind() { ty::TyKind::Ref(_, ty, mutability) => { // Use unfolded references. @@ -3795,13 +3977,12 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { "In ProcedureEncoder::encode_local_variable_permission the local \ {local:?} is fake but override_span is None", ), - self.mir.span + self.mir.span, )); } self.mir_encoder.get_local_span(local.into()) }; - let field = self.encoder.encode_dereference_field(*ty) - .with_span(span)?; + let field = self.encoder.encode_dereference_field(*ty).with_span(span)?; let place = vir::Expr::from(encoded_local).field(field); let perm_amount = match mutability { Mutability::Mut => vir::PermAmount::Write, @@ -3832,13 +4013,8 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { &self, contract: &ProcedureContract<'tcx>, substs: GenericArgsRef<'tcx>, - override_spans: FxHashMap // spans for fake locals - ) -> SpannedEncodingResult<( - vir::Expr, - Vec, - vir::Expr, - vir::Expr, - )> { + override_spans: FxHashMap, // spans for fake locals + ) -> SpannedEncodingResult<(vir::Expr, Vec, vir::Expr, vir::Expr)> { let borrow_infos = &contract.borrow_infos; let maybe_blocked_paths = if !borrow_infos.is_empty() { assert_eq!( @@ -3876,12 +4052,15 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { type_spec.push(access); } }; - let access = self.encode_local_variable_permission( - *local, - override_spans.get(local).copied() - )?; + let access = + self.encode_local_variable_permission(*local, override_spans.get(local).copied())?; match access { - vir::Expr::BinOp( vir::BinOp {op_kind: vir::BinaryOpKind::And, left: box access1, right: box access2, ..} ) => { + vir::Expr::BinOp(vir::BinOp { + op_kind: vir::BinaryOpKind::And, + left: box access1, + right: box access2, + .. + }) => { add(access1); add(access2); } @@ -3896,24 +4075,26 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { .map(|local| self.encode_prusti_local(*local).into()) .collect(); - let func_spec: Vec = contract.functional_precondition( - self.encoder.env(), - substs, - ).iter() - .map(|(assertion, assertion_substs)| self.encoder.encode_assertion( - assertion, - None, - &encoded_args, - None, - false, - self.proc_def_id, - assertion_substs, - )) + let func_spec: Vec = contract + .functional_precondition(self.encoder.env(), substs) + .iter() + .map(|(assertion, assertion_substs)| { + self.encoder.encode_assertion( + assertion, + None, + &encoded_args, + None, + false, + self.proc_def_id, + assertion_substs, + ) + }) .collect::, _>>()?; // TODO(tymap): do this with the previous step ... let precondition_spans = MultiSpan::from_spans( - contract.functional_precondition(self.encoder.env(), substs) + contract + .functional_precondition(self.encoder.env(), substs) .iter() .map(|(ts, _)| self.encoder.env().query.get_def_span(ts)) .collect(), @@ -3926,10 +4107,9 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { let ty = self.locals.get_type(*arg); if !ty.is_unsafe_ptr() && !self.encoder.is_pure(contract.def_id, Some(substs)) { invs_spec.push( - self.encoder.encode_invariant_func_app( - ty, - self.encode_prusti_local(*arg).into(), - ).with_span(precondition_spans.clone())? + self.encoder + .encode_invariant_func_app(ty, self.encode_prusti_local(*arg).into()) + .with_span(precondition_spans.clone())?, ); } } @@ -3950,13 +4130,15 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { Option, )> { // Encode arguments and return - let encoded_args = self.procedure_contract() + let encoded_args = self + .procedure_contract() .args .iter() .map(|local| self.encode_prusti_local(*local).into()) .collect::>(); let encoded_return = self - .encode_prusti_local(self.procedure_contract().returned_value).into(); + .encode_prusti_local(self.procedure_contract().returned_value) + .into(); debug!("procedure_contract: {:?}", self.procedure_contract()); @@ -3967,41 +4149,53 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { if let SpecificationItem::Refined(from, to) = &procedure_spec.pres { // See comment in `ProcedureContractGeneric::functional_precondition`. - let trait_substs = self.encoder.env().query.find_trait_method_substs( - self.proc_def_id, - self.substs, - ).unwrap().1; + let trait_substs = self + .encoder + .env() + .query + .find_trait_method_substs(self.proc_def_id, self.substs) + .unwrap() + .1; - let from_pre = from.iter() - .map(|spec| self.encoder.encode_assertion( - spec, - None, - &encoded_args, - None, - false, - self.proc_def_id, - trait_substs, - )) + let from_pre = from + .iter() + .map(|spec| { + self.encoder.encode_assertion( + spec, + None, + &encoded_args, + None, + false, + self.proc_def_id, + trait_substs, + ) + }) .collect::, _>>()? .into_iter() .conjoin(); - let to_pre = to.iter() - .map(|spec| self.encoder.encode_assertion( - spec, - None, - &encoded_args, - None, - false, - self.proc_def_id, - self.substs, - )) + let to_pre = to + .iter() + .map(|spec| { + self.encoder.encode_assertion( + spec, + None, + &encoded_args, + None, + false, + self.proc_def_id, + self.substs, + ) + }) .collect::, _>>()? .into_iter() .conjoin(); // The spans are used for error reporting - let spec_functions_span = MultiSpan::from_spans(from.iter().chain(to.iter()) - .map(|spec_def_id| self.encoder.env().query.get_def_span(spec_def_id)).collect() + let spec_functions_span = MultiSpan::from_spans( + from.iter() + .chain(to.iter()) + .map(|spec_def_id| self.encoder.env().query.get_def_span(spec_def_id)) + .collect(), ); weakening = Some(RefinementCheckExpr { @@ -4012,43 +4206,53 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { if let SpecificationItem::Refined(from, to) = &procedure_spec.posts { // See comment in `ProcedureContractGeneric::functional_precondition`. - let trait_substs = self.encoder.env().query.find_trait_method_substs( - self.proc_def_id, - self.substs, - ).unwrap().1; + let trait_substs = self + .encoder + .env() + .query + .find_trait_method_substs(self.proc_def_id, self.substs) + .unwrap() + .1; let from_post = from .iter() - .map(|spec| self.encoder.encode_assertion( - spec, - Some(pre_label), - &encoded_args, - Some(&encoded_return), - false, - self.proc_def_id, - trait_substs, - )) + .map(|spec| { + self.encoder.encode_assertion( + spec, + Some(pre_label), + &encoded_args, + Some(&encoded_return), + false, + self.proc_def_id, + trait_substs, + ) + }) .collect::, _>>()? .into_iter() .conjoin(); let to_post = to .iter() - .map(|spec| self.encoder.encode_assertion( - spec, - Some(pre_label), - &encoded_args, - Some(&encoded_return), - false, - self.proc_def_id, - self.substs, - )) + .map(|spec| { + self.encoder.encode_assertion( + spec, + Some(pre_label), + &encoded_args, + Some(&encoded_return), + false, + self.proc_def_id, + self.substs, + ) + }) .collect::, _>>()? .into_iter() .conjoin(); // The spans are used for error reporting - let spec_functions_span = MultiSpan::from_spans(from.iter().chain(to.iter()) - .map(|spec_def_id| self.encoder.env().query.get_def_span(spec_def_id)).collect() + let spec_functions_span = MultiSpan::from_spans( + from.iter() + .chain(to.iter()) + .map(|spec_def_id| self.encoder.env().query.get_def_span(spec_def_id)) + .collect(), ); let strengthening_expr = self.wrap_arguments_into_old( @@ -4086,51 +4290,47 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { ) -> SpannedEncodingResult<()> { self.cfg_method .add_stmt(start_cfg_block, vir::Stmt::comment("Preconditions:")); - let (type_spec, mandatory_type_spec, invs_spec, func_spec) = - self.encode_precondition_expr( + let (type_spec, mandatory_type_spec, invs_spec, func_spec) = self + .encode_precondition_expr( self.procedure_contract(), self.substs, - FxHashMap::default() + FxHashMap::default(), )?; self.cfg_method.add_stmt( start_cfg_block, - vir::Stmt::Inhale( vir::Inhale { - expr: type_spec}), + vir::Stmt::Inhale(vir::Inhale { expr: type_spec }), ); self.cfg_method.add_stmt( start_cfg_block, - vir::Stmt::Inhale( vir::Inhale { + vir::Stmt::Inhale(vir::Inhale { expr: mandatory_type_spec.into_iter().conjoin(), }), ); self.cfg_method.add_stmt( start_cfg_block, - vir::Stmt::Inhale( vir::Inhale { - expr: invs_spec, - }), + vir::Stmt::Inhale(vir::Inhale { expr: invs_spec }), ); // Weakening assertion must be put before inhaling the precondition, otherwise the weakening // soundness check becomes trivially satisfied. if let Some(weakening_spec) = weakening_spec { - let pos = self.register_error(weakening_spec.spec_functions_span, ErrorCtxt::AssertMethodPreconditionWeakening); + let pos = self.register_error( + weakening_spec.spec_functions_span, + ErrorCtxt::AssertMethodPreconditionWeakening, + ); self.cfg_method.add_stmt( start_cfg_block, - vir::Stmt::Assert( vir::Assert { + vir::Stmt::Assert(vir::Assert { expr: weakening_spec.refinement_check_expr, - position: pos + position: pos, }), ); } self.cfg_method.add_stmt( start_cfg_block, - vir::Stmt::Inhale( vir::Inhale { - expr: func_spec - }), - ); - self.cfg_method.add_stmt( - start_cfg_block, - vir::Stmt::label(PRECONDITION_LABEL), + vir::Stmt::Inhale(vir::Inhale { expr: func_spec }), ); + self.cfg_method + .add_stmt(start_cfg_block, vir::Stmt::label(PRECONDITION_LABEL)); Ok(()) } @@ -4179,9 +4379,9 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { Mutability::Not => vir::PermAmount::Read, Mutability::Mut => vir::PermAmount::Write, }; - let (place_expr, place_ty, _) = self.encode_generic_place( - contract.def_id, location, place - ).with_span(span)?; + let (place_expr, place_ty, _) = self + .encode_generic_place(contract.def_id, location, place) + .with_span(span)?; let vir_access = vir::Expr::pred_permission(place_expr.clone().old(label), perm_amount).unwrap(); if !self.encoder.is_pure(contract.def_id, Some(substs)) { @@ -4204,7 +4404,12 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { .iter() .map(|(place, mutability)| encode_place_perm(*place, *mutability, pre_label)) .collect::>()?; - if let Some(typed::Pledge { reference, lhs: body_lhs, rhs: body_rhs}) = pledges.first() { + if let Some(typed::Pledge { + reference, + lhs: body_lhs, + rhs: body_rhs, + }) = pledges.first() + { debug!( "pledge reference={:?} lhs={:?} rhs={:?}", reference, body_lhs, body_rhs @@ -4248,9 +4453,9 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { &encoded_args, )?; let ty = self.locals.get_type(contract.returned_value); - let return_span = self.mir_encoder.get_local_span( - contract.returned_value.into() - ); + let return_span = self + .mir_encoder + .get_local_span(contract.returned_value.into()); let (encoded_deref, ..) = self .mir_encoder .encode_deref(encoded_return, ty) @@ -4266,12 +4471,8 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { lhs.push(assertion_lhs); rhs.push(assertion_rhs); } - let lhs = lhs - .into_iter() - .conjoin(); - let rhs = rhs - .into_iter() - .conjoin(); + let lhs = lhs.into_iter().conjoin(); + let rhs = rhs.into_iter().conjoin(); Ok(Some((lhs, rhs))) } else { Ok(None) @@ -4304,7 +4505,12 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { } else { // If the argument is not a reference, we wrap entire path into old. assertion = assertion.fold_expr(|e| { - if let vir::Expr::FuncApp(vir::FuncApp { function_name, arguments, .. }) = &e { + if let vir::Expr::FuncApp(vir::FuncApp { + function_name, + arguments, + .. + }) = &e + { // If `assertion` is e.g. a `foo(snap(_1))` with an `_1: T` and `fn foo(x: &T)` we cannot // wrap `foo(snap(old[pre](_1)))`, but should instead wrap as `foo(old[pre](snap(_1)))` // TODO: this could all be fixed by making all arguments into fields (e.g. `_1.local`). @@ -4368,9 +4574,9 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { place, mutability ); // TODO: Use a better span - let (place_expr, place_ty, _) = self.encode_generic_place( - contract.def_id, location, *place - ).with_span(self.mir.span)?; + let (place_expr, place_ty, _) = self + .encode_generic_place(contract.def_id, location, *place) + .with_span(self.mir.span)?; let old_place_expr = place_expr.clone().old(pre_label); let mut add_type_spec = |perm_amount| { let permissions = @@ -4404,9 +4610,16 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { .iter() .map(|local| self.encode_prusti_local(*local).into()) .collect(); - trace!("encode_postcondition_expr: encoded_args {:?} ({:?}) as {:?}", contract.args, - contract.args.iter().map(|a| self.locals.get_type(*a)).collect::>(), - encoded_args); + trace!( + "encode_postcondition_expr: encoded_args {:?} ({:?}) as {:?}", + contract.args, + contract + .args + .iter() + .map(|a| self.locals.get_type(*a)) + .collect::>(), + encoded_args + ); let encoded_return: vir::Expr = self.encode_prusti_local(contract.returned_value).into(); @@ -4416,13 +4629,10 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { self.mir.span }; let mut magic_wands = Vec::new(); - if let Some((mut lhs, mut rhs)) = self.encode_postcondition_magic_wand( - location, - contract, - pre_label, - post_label, - substs, - ).with_span(span)? { + if let Some((mut lhs, mut rhs)) = self + .encode_postcondition_magic_wand(location, contract, pre_label, post_label, substs) + .with_span(span)? + { if let Some((location, fake_exprs)) = magic_wand_store_info { let replace_fake_exprs = |mut expr: vir::Expr| -> vir::Expr { for (fake_arg, arg_expr) in fake_exprs.iter() { @@ -4432,25 +4642,23 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { }; lhs = replace_fake_exprs(lhs); rhs = replace_fake_exprs(rhs); - lhs = self.encoder.patch_snapshots(lhs) - .with_span(self.mir.span)?; - rhs = self.encoder.patch_snapshots(rhs) - .with_span(self.mir.span)?; + lhs = self.encoder.patch_snapshots(lhs).with_span(self.mir.span)?; + rhs = self.encoder.patch_snapshots(rhs).with_span(self.mir.span)?; debug!("Insert ({:?} {:?}) at {:?}", lhs, rhs, location); self.magic_wand_at_location .insert(location, (post_label.to_string(), lhs.clone(), rhs.clone())); } - magic_wands.push(vir::Expr::magic_wand(lhs, rhs, loan.map(|l| l.index().into()))); + magic_wands.push(vir::Expr::magic_wand( + lhs, + rhs, + loan.map(|l| l.index().into()), + )); } // Encode permissions for return type // TODO: Clean-up: remove unnecessary Option. - let return_perm = Some( - self.encode_local_variable_permission( - contract.returned_value, - None - )? - ); + let return_perm = + Some(self.encode_local_variable_permission(contract.returned_value, None)?); // Encode functional specification let mut func_spec = vec![]; @@ -4469,12 +4677,8 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { let assertion_span = self.encoder.env().query.get_def_span(typed_assertion); func_spec_spans.push(assertion_span); let assertion_pos = self.mir_encoder.register_span(assertion_span); - assertion = self.wrap_arguments_into_old( - assertion, - pre_label, - contract, - &encoded_args, - )?; + assertion = + self.wrap_arguments_into_old(assertion, pre_label, contract, &encoded_args)?; func_spec.push(assertion.set_default_pos(assertion_pos)); } let postcondition_span = MultiSpan::from_spans(func_spec_spans); @@ -4483,14 +4687,18 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { // Encode invariant for return value if !self.encoder.is_pure(contract.def_id, Some(substs)) { invs_spec.push( - self.encoder.encode_invariant_func_app( - self.locals.get_type(contract.returned_value), - encoded_return, - ).with_span(postcondition_span)? + self.encoder + .encode_invariant_func_app( + self.locals.get_type(contract.returned_value), + encoded_return, + ) + .with_span(postcondition_span)?, ); } - let full_func_spec = func_spec.into_iter().conjoin() + let full_func_spec = func_spec + .into_iter() + .conjoin() .set_default_pos(func_spec_pos); Ok(( @@ -4525,9 +4733,16 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { } impl<'a> vir::ExprFolder for OldReplacer<'a> { #[allow(clippy::map_entry)] - fn fold_labelled_old(&mut self, vir::LabelledOld {label, base, position}: vir::LabelledOld) -> vir::Expr { + fn fold_labelled_old( + &mut self, + vir::LabelledOld { + label, + base, + position, + }: vir::LabelledOld, + ) -> vir::Expr { let base = self.fold_boxed(base); - let expr = vir::Expr::LabelledOld( vir::LabelledOld { + let expr = vir::Expr::LabelledOld(vir::LabelledOld { label: label.clone(), base, position, @@ -4579,14 +4794,18 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { let span = self.mir.source_info(location).span; // Package magic wand(s) - if let Some((lhs, rhs)) = self.encode_postcondition_magic_wand( - None, - self.procedure_contract(), - pre_label, - post_label, - self.substs, - ).with_span(span)? { - let pos = self.register_error(self.mir.span, ErrorCtxt::PackageMagicWandForPostcondition); + if let Some((lhs, rhs)) = self + .encode_postcondition_magic_wand( + None, + self.procedure_contract(), + pre_label, + post_label, + self.substs, + ) + .with_span(span)? + { + let pos = + self.register_error(self.mir.span, ErrorCtxt::PackageMagicWandForPostcondition); let blocker = mir::RETURN_PLACE; // TODO: Check if it really is always start and not the mid point. @@ -4594,28 +4813,26 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { .polonius_info() .get_point(location, facts::PointType::Start); - let opt_region = self.polonius_info() - .place_regions - .for_local(blocker); + let opt_region = self.polonius_info().place_regions.for_local(blocker); let mut package_stmts = if let Some(region) = opt_region { - let (all_loans, zombie_loans) = self - .polonius_info() - .get_all_loans_kept_alive_by(start_point, region); - self.encode_expiration_of_loans(all_loans, &zombie_loans, location, None, true)? - } else { - // This happens when encoding the following function - // ``` - // struct MyStruct<'tcx>(TyCtxt<'tcx>); - // fn foo(tcx: TyCtxt) -> MyStruct { - // MyStruct(tcx) - // } - // ``` - return Err(SpannedEncodingError::unsupported( - "the encoding of pledges does not supporte this \ + let (all_loans, zombie_loans) = self + .polonius_info() + .get_all_loans_kept_alive_by(start_point, region); + self.encode_expiration_of_loans(all_loans, &zombie_loans, location, None, true)? + } else { + // This happens when encoding the following function + // ``` + // struct MyStruct<'tcx>(TyCtxt<'tcx>); + // fn foo(tcx: TyCtxt) -> MyStruct { + // MyStruct(tcx) + // } + // ``` + return Err(SpannedEncodingError::unsupported( + "the encoding of pledges does not supporte this \ kind of reborrowing", - self.mir_encoder.get_span_of_location(location), - )); - }; + self.mir_encoder.get_span_of_location(location), + )); + }; // We need to make sure that the lhs of the magic wand is // fully folded before the label. @@ -4643,10 +4860,10 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { let arg_span = self.mir_encoder.get_local_span(arg_index); if is_reference(arg_ty) { let encoded_arg = self.mir_encoder.encode_local(arg_index)?; - let (deref_place, ..) = - self.mir_encoder - .encode_deref(encoded_arg.into(), arg_ty) - .with_span(arg_span)?; + let (deref_place, ..) = self + .mir_encoder + .encode_deref(encoded_arg.into(), arg_ty) + .with_span(arg_span)?; let old_deref_place = deref_place.clone().old(pre_label); package_stmts.extend(self.encode_transfer_permissions( deref_place, @@ -4684,11 +4901,16 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { "We can have at most one magic wand in the postcondition." ); for (path, _) in borrow_infos[0].blocking_paths.clone().iter() { - let (encoded_place, _, _) = self.encode_generic_place( - self.procedure_contract().def_id, None, *path - ).with_span(span)?; + let (encoded_place, _, _) = self + .encode_generic_place(self.procedure_contract().def_id, None, *path) + .with_span(span)?; let old_place = encoded_place.clone().old(post_label.clone()); - stmts.extend(self.encode_transfer_permissions(old_place, encoded_place, location, true)); + stmts.extend(self.encode_transfer_permissions( + old_place, + encoded_place, + location, + true, + )); } } @@ -4705,29 +4927,27 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { // This clone is only due to borrow checker restrictions let contract = self.procedure_contract().clone(); - self.cfg_method.add_stmt(return_cfg_block, vir::Stmt::comment("Exhale postcondition")); + self.cfg_method + .add_stmt(return_cfg_block, vir::Stmt::comment("Exhale postcondition")); let postcondition_label = self.cfg_method.get_fresh_label_name(); - self.cfg_method.add_stmt(return_cfg_block, vir::Stmt::label(postcondition_label.clone())); + self.cfg_method.add_stmt( + return_cfg_block, + vir::Stmt::label(postcondition_label.clone()), + ); - let ( - type_spec, - return_type_spec, - invs_spec, - func_spec, - magic_wands, - _, - ) = self.encode_postcondition_expr( - None, - &contract, - PRECONDITION_LABEL, - &postcondition_label, - None, - false, - None, - true, - self.substs, - )?; + let (type_spec, return_type_spec, invs_spec, func_spec, magic_wands, _) = self + .encode_postcondition_expr( + None, + &contract, + PRECONDITION_LABEL, + &postcondition_label, + None, + false, + None, + true, + self.substs, + )?; let type_inv_pos = self.register_error( self.mir.span, @@ -4788,10 +5008,7 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { vir::PermAmount::Write, ) .unwrap(); - for stmt in self - .encode_obtain(deref_pred, type_inv_pos) - .drain(..) - { + for stmt in self.encode_obtain(deref_pred, type_inv_pos).drain(..) { self.cfg_method.add_stmt(return_cfg_block, stmt); } @@ -4819,25 +5036,26 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { self.cfg_method.add_stmt( return_cfg_block, - vir::Stmt::Assign( vir::Assign { + vir::Stmt::Assign(vir::Assign { target: var, source: encoded_deref, - kind: vir::AssignKind::Move + kind: vir::AssignKind::Move, }), ); } } // Fold the result. - self.cfg_method.add_stmt( - return_cfg_block, - vir::Stmt::comment("Fold the result"), - ); + self.cfg_method + .add_stmt(return_cfg_block, vir::Stmt::comment("Fold the result")); let ty = self.locals.get_type(contract.returned_value); let encoded_return: vir::Expr = self.encode_prusti_local(contract.returned_value).into(); - let return_span = self.mir_encoder.get_local_span(contract.returned_value.into()); + let return_span = self + .mir_encoder + .get_local_span(contract.returned_value.into()); let encoded_return_expr = if is_reference(ty) { - let (encoded_deref, ..) = self.mir_encoder + let (encoded_deref, ..) = self + .mir_encoder .encode_deref(encoded_return, ty) .with_span(return_span)?; encoded_deref @@ -4848,7 +5066,7 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { .mir_encoder .encode_place_predicate_permission(encoded_return_expr, vir::PermAmount::Write) .unwrap(); - let obtain_return_stmt = vir::Stmt::Obtain( vir::Obtain { + let obtain_return_stmt = vir::Stmt::Obtain(vir::Obtain { expr: return_pred, position: type_inv_pos, }); @@ -4861,12 +5079,15 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { vir::Stmt::comment("Assert possible strengthening"), ); if let Some(strengthening_spec) = strengthening_spec { - let patched_strengthening_spec = - self.replace_old_places_with_ghost_vars(None, strengthening_spec.refinement_check_expr); - let pos = self.register_error(strengthening_spec.spec_functions_span, ErrorCtxt::AssertMethodPostconditionStrengthening); + let patched_strengthening_spec = self + .replace_old_places_with_ghost_vars(None, strengthening_spec.refinement_check_expr); + let pos = self.register_error( + strengthening_spec.spec_functions_span, + ErrorCtxt::AssertMethodPostconditionStrengthening, + ); self.cfg_method.add_stmt( return_cfg_block, - vir::Stmt::Assert( vir::Assert { + vir::Stmt::Assert(vir::Assert { expr: patched_strengthening_spec, position: pos, }), @@ -4882,7 +5103,7 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { let patched_func_spec = self.replace_old_places_with_ghost_vars(None, func_spec); self.cfg_method.add_stmt( return_cfg_block, - vir::Stmt::Assert( vir::Assert { + vir::Stmt::Assert(vir::Assert { expr: patched_func_spec, position: func_pos, }), @@ -4896,7 +5117,7 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { let patched_invs_spec = self.replace_old_places_with_ghost_vars(None, invs_spec); self.cfg_method.add_stmt( return_cfg_block, - vir::Stmt::Assert( vir::Assert { + vir::Stmt::Assert(vir::Assert { expr: patched_invs_spec, position: type_inv_pos, }), @@ -4912,7 +5133,7 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { debug_assert!(!perm_pos.is_default()); self.cfg_method.add_stmt( return_cfg_block, - vir::Stmt::Exhale( vir::Exhale { + vir::Stmt::Exhale(vir::Exhale { expr: patched_type_spec, position: perm_pos, }), @@ -4925,7 +5146,7 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { if let Some(access) = return_type_spec { self.cfg_method.add_stmt( return_cfg_block, - vir::Stmt::Exhale( vir::Exhale { + vir::Stmt::Exhale(vir::Exhale { expr: access, position: perm_pos, }), @@ -4939,7 +5160,7 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { for magic_wand in magic_wands { self.cfg_method.add_stmt( return_cfg_block, - vir::Stmt::Exhale( vir::Exhale { + vir::Stmt::Exhale(vir::Exhale { expr: magic_wand, position: perm_pos, }), @@ -4985,7 +5206,7 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { place: &vir::Expr, ) -> vir::Expr { let tmp_var = self.get_pure_var_for_preserving_value(loop_head, place); - vir::Expr::BinOp ( vir::BinOp { + vir::Expr::BinOp(vir::BinOp { op_kind: vir::BinaryOpKind::EqCmp, left: Box::new(tmp_var.into()), right: Box::new(place.clone()), @@ -5008,7 +5229,7 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { let snap_array = vir::Expr::snap_app(array_base); let old_snap_array = vir::Expr::old(snap_array.clone(), old_label); - vir_expr!{ [snap_array] == [old_snap_array] } + vir_expr! { [snap_array] == [old_snap_array] } } /// Arguments: @@ -5045,17 +5266,21 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { let enclosing_permission_forest = if loops.len() > 1 { let next_to_last = loops.len() - 2; let enclosing_loop_head = loops[next_to_last]; - Some(self.loop_encoder.compute_loop_invariant( - enclosing_loop_head, - self.cached_loop_invariant_block[&enclosing_loop_head], - ).map_err(|err| match err { - LoopAnalysisError::UnsupportedPlaceContext(place_ctxt, loc) => { - SpannedEncodingError::internal( - format!("loop uses the unexpected PlaceContext '{place_ctxt:?}'"), - self.mir_encoder.get_span_of_location(loc), + Some( + self.loop_encoder + .compute_loop_invariant( + enclosing_loop_head, + self.cached_loop_invariant_block[&enclosing_loop_head], ) - } - })?) + .map_err(|err| match err { + LoopAnalysisError::UnsupportedPlaceContext(place_ctxt, loc) => { + SpannedEncodingError::internal( + format!("loop uses the unexpected PlaceContext '{place_ctxt:?}'"), + self.mir_encoder.get_span_of_location(loc), + ) + } + })?, + ) } else { None }; @@ -5081,16 +5306,21 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { ExprOrArrayBase::ArrayBase(b) | ExprOrArrayBase::SliceBase(b) => (b, true), }; - debug!("kind={:?} mir_place={:?} encoded_place={:?} ty={:?}", kind, mir_place, encoded_place, ty); + debug!( + "kind={:?} mir_place={:?} encoded_place={:?} ty={:?}", + kind, mir_place, encoded_place, ty + ); match kind { // Gives read permission to this node. It must not be a leaf node. PermissionKind::ReadNode => { if is_array_access { // if it's already there, it's at least read -> nothing to do here - array_pred_perms.entry(encoded_place) + array_pred_perms + .entry(encoded_place) .or_insert(vir::PermAmount::Read); } else { - let perm = vir::Expr::acc_permission(encoded_place, vir::PermAmount::Read); + let perm = + vir::Expr::acc_permission(encoded_place, vir::PermAmount::Read); permissions.push(perm); } } @@ -5100,7 +5330,8 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { if is_array_access { array_pred_perms.insert(encoded_place, vir::PermAmount::Write); } else { - let perm = vir::Expr::acc_permission(encoded_place, vir::PermAmount::Write); + let perm = + vir::Expr::acc_permission(encoded_place, vir::PermAmount::Write); permissions.push(perm); } } @@ -5118,7 +5349,8 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { .loop_encoder .is_definitely_initialised(mir_place, loop_head); debug!(" perm_amount={} def_init={}", perm_amount, def_init); - if let Some(base) = utils::try_pop_deref(self.encoder.env().tcx(), mir_place) + if let Some(base) = + utils::try_pop_deref(self.encoder.env().tcx(), mir_place) { // will panic if attempting to encode unsupported type let ref_ty = self.mir_encoder.encode_place(base).unwrap().1; @@ -5159,8 +5391,7 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { &field_place, )); } - if def_init - && !(mutbl == &Mutability::Not && drop_read_references) + if def_init && !(mutbl == &Mutability::Not && drop_read_references) { permissions.push( vir::Expr::pred_permission(field_place, perm_amount) @@ -5170,12 +5401,18 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { } _ => { if is_array_access { - array_pred_perms.entry(encoded_place) - .and_modify(|e| if perm_amount == vir::PermAmount::Write { *e = vir::PermAmount::Write; }) + array_pred_perms + .entry(encoded_place) + .and_modify(|e| { + if perm_amount == vir::PermAmount::Write { + *e = vir::PermAmount::Write; + } + }) .or_insert(perm_amount); } else { permissions.push( - vir::Expr::pred_permission(encoded_place, perm_amount).unwrap(), + vir::Expr::pred_permission(encoded_place, perm_amount) + .unwrap(), ); } @@ -5186,23 +5423,30 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { // that we will lose information about the children of that // place after the loop and we need to preserve it via local // variables. - let encoded_child = self.mir_encoder.encode_place(child_place)?.0; + let encoded_child = + self.mir_encoder.encode_place(child_place)?.0; match encoded_child.into_array_base() { ExprOrArrayBase::Expr(e) => { - equalities.push(self.construct_value_preserving_equality( - loop_head, - &e, - )); + equalities.push( + self.construct_value_preserving_equality( + loop_head, &e, + ), + ); } ExprOrArrayBase::ArrayBase(b) => { - let eq = self.construct_value_preserving_array_equality(loop_head, b); + let eq = self + .construct_value_preserving_array_equality( + loop_head, b, + ); // arrays can be mentioned multiple times, so we // need to check here if !equalities.contains(&eq) { equalities.push(eq); } } - ExprOrArrayBase::SliceBase(_) => unimplemented!("slices in loops not yet implemented"), + ExprOrArrayBase::SliceBase(_) => unimplemented!( + "slices in loops not yet implemented" + ), } } } @@ -5225,21 +5469,24 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { trace!("array_pred_perms: {:?}", array_pred_perms); for (place, perm) in array_pred_perms.into_iter() { permissions.push( - vir::Expr::pred_permission(place, perm) - .expect("invalid place in array_pred_perms") + vir::Expr::pred_permission(place, perm).expect("invalid place in array_pred_perms"), ); } // encode type invariants let mut invs_spec = Vec::new(); for permission in &permissions { - if let vir::Expr::PredicateAccessPredicate( vir::PredicateAccessPredicate {predicate_type, argument, ..}) = permission { + if let vir::Expr::PredicateAccessPredicate(vir::PredicateAccessPredicate { + predicate_type, + argument, + .. + }) = permission + { let ty = self.encoder.decode_type_predicate_type(predicate_type)?; if !self.encoder.is_pure(self.proc_def_id, Some(self.substs)) { - let inv_func_app = self.encoder.encode_invariant_func_app( - ty, - (**argument).clone(), - )?; + let inv_func_app = self + .encoder + .encode_invariant_func_app(ty, (**argument).clone())?; invs_spec.push(inv_func_app); } } @@ -5247,20 +5494,18 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { trace!( "[exit] encode_loop_invariant_permissions permissions={}", - permissions - .iter().fold(String::new(), |mut output, p| { - let _ = write!(output, "{p}, "); - output - }) + permissions.iter().fold(String::new(), |mut output, p| { + let _ = write!(output, "{p}, "); + output + }) ); trace!( "[exit] encode_loop_invariant_permissions equalities={}", - equalities - .iter().fold(String::new(), |mut output, p| { - let _ = write!(output, "{p}, "); - output - }) + equalities.iter().fold(String::new(), |mut output, p| { + let _ = write!(output, "{p}, "); + output + }) ); Ok((permissions, equalities, invs_spec)) @@ -5309,8 +5554,12 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { for stmt in &self.mir.basic_blocks[bbi].statements { if let mir::StatementKind::Assign(box ( _, - mir::Rvalue::Aggregate(box mir::AggregateKind::Closure(cl_def_id, cl_substs), _), - )) = stmt.kind { + mir::Rvalue::Aggregate( + box mir::AggregateKind::Closure(cl_def_id, cl_substs), + _, + ), + )) = stmt.kind + { if let Some(spec) = self.encoder.get_loop_specs(cl_def_id) { encoded_specs.push(self.encoder.encode_invariant( self.mir, @@ -5319,7 +5568,9 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { cl_substs, )?); let invariant = match spec { - prusti_interface::specs::typed::LoopSpecification::Invariant(inv) => inv, + prusti_interface::specs::typed::LoopSpecification::Invariant(inv) => { + inv + } _ => continue, }; encoded_spec_spans.push(self.encoder.env().tcx().def_span(invariant)); @@ -5343,9 +5594,9 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { } let (func_spec, func_spec_span) = self.encode_loop_invariant_specs(loop_head, loop_inv_block)?; - let (permissions, equalities, invs_spec) = - self.encode_loop_invariant_permissions(loop_head, loop_inv_block, true) - .with_span(func_spec_span.clone())?; + let (permissions, equalities, invs_spec) = self + .encode_loop_invariant_permissions(loop_head, loop_inv_block, true) + .with_span(func_spec_span.clone())?; // TODO: use different positions, and generate different error messages, for the exhale // before the loop and after the loop body @@ -5378,7 +5629,7 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { stmts.push(vir::Stmt::label(label)); } for (place, field) in &self.pure_var_for_preserving_value_map[&loop_head] { - stmts.push(vir::Stmt::Assign( vir::Assign { + stmts.push(vir::Stmt::Assign(vir::Assign { target: field.into(), source: place.clone(), kind: vir::AssignKind::Ghost, @@ -5387,28 +5638,28 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { } assert!(!assert_pos.is_default()); let obtain_predicates = permissions.iter().map(|p| { - vir::Stmt::Obtain( vir::Obtain { + vir::Stmt::Obtain(vir::Obtain { expr: p.clone(), position: assert_pos, }) // TODO: Use a better position. }); stmts.extend(obtain_predicates); - stmts.push(vir::Stmt::Assert( vir::Assert { + stmts.push(vir::Stmt::Assert(vir::Assert { expr: func_spec.into_iter().conjoin(), position: assert_pos, })); - stmts.push(vir::Stmt::Assert( vir::Assert { + stmts.push(vir::Stmt::Assert(vir::Assert { expr: invs_spec.into_iter().conjoin(), position: exhale_pos, })); let equalities_expr = equalities.into_iter().conjoin(); - stmts.push(vir::Stmt::Assert( vir::Assert { + stmts.push(vir::Stmt::Assert(vir::Assert { expr: equalities_expr, position: exhale_pos, })); let permission_expr = permissions.into_iter().conjoin(); - stmts.push(vir::Stmt::Exhale( vir::Exhale { + stmts.push(vir::Stmt::Exhale(vir::Exhale { expr: permission_expr, position: exhale_pos, })); @@ -5431,13 +5682,13 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { let mut stmts = vec![vir::Stmt::comment(format!( "Inhale the loop permissions invariant of block {loop_head:?}" ))]; - stmts.push(vir::Stmt::Inhale( vir::Inhale { + stmts.push(vir::Stmt::Inhale(vir::Inhale { expr: permission_expr, })); - stmts.push(vir::Stmt::Inhale( vir::Inhale { + stmts.push(vir::Stmt::Inhale(vir::Inhale { expr: equality_expr, })); - stmts.push(vir::Stmt::Inhale( vir::Inhale { + stmts.push(vir::Stmt::Inhale(vir::Inhale { expr: invs_spec.into_iter().conjoin(), })); Ok(stmts) @@ -5456,7 +5707,7 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { let mut stmts = vec![vir::Stmt::comment(format!( "Inhale the loop fnspec invariant of block {loop_head:?}" ))]; - stmts.push(vir::Stmt::Inhale( vir::Inhale { + stmts.push(vir::Stmt::Inhale(vir::Inhale { expr: func_spec.into_iter().conjoin(), })); Ok((stmts, func_spec_span)) @@ -5466,7 +5717,8 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { let var_name = self.locals.get_name(local); let typ = self .encoder - .encode_type(self.locals.get_type(local)).unwrap(); // will panic if attempting to encode unsupported type + .encode_type(self.locals.get_type(local)) + .unwrap(); // will panic if attempting to encode unsupported type vir::LocalVar::new(var_name, typ) } @@ -5497,9 +5749,15 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { ) -> EncodingResult<(vir::Expr, ty::Ty<'tcx>, Option)> { let mir_encoder = if let Some(location) = location { let block = &self.mir.basic_blocks[location.block]; - assert_eq!(block.statements.len(), location.statement_index, "expected terminator location"); + assert_eq!( + block.statements.len(), + location.statement_index, + "expected terminator location" + ); match &block.terminator().kind { - mir::TerminatorKind::Call{ args, destination, .. } => { + mir::TerminatorKind::Call { + args, destination, .. + } => { let tcx = self.encoder.env().tcx(); let arg_tys = args.iter().map(|arg| arg.ty(self.mir, tcx)).collect(); let return_ty = destination.ty(self.mir, tcx).ty; @@ -5509,9 +5767,11 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { } } else { // FIXME: why are we getting the MIR body for this? - let mir = self.encoder.env().body.get_impure_fn_body_identity( - containing_def_id.expect_local(), - ); + let mir = self + .encoder + .env() + .body + .get_impure_fn_body_identity(containing_def_id.expect_local()); let return_ty = mir.return_ty(); let arg_tys = mir.args_iter().map(|arg| mir.local_decls[arg].ty).collect(); FakeMirEncoder::new(self.encoder, arg_tys, return_ty) @@ -5523,7 +5783,7 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { } Place::SubstitutedPlace { substituted_root, - place + place, } => { let (place_encoding, ty, variant) = mir_encoder.encode_place(place)?; let expr = place_encoding.try_into_expr()?; @@ -5533,7 +5793,7 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { } use vir::ExprFolder; impl ExprFolder for RootReplacer { - fn fold_local(&mut self, vir::Local {position, ..}: vir::Local) -> vir::Expr { + fn fold_local(&mut self, vir::Local { position, .. }: vir::Local) -> vir::Expr { vir::Expr::local_with_pos(self.new_root.clone(), position) } } @@ -5618,15 +5878,20 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { // inhale lookup_pure(array, index) == encoded_rhs // // now we have all the contents as before, just one item updated - let (encoded_array, mut stmts) = self.postprocess_place_encoding( - base, - ArrayAccessKind::Shared, // shouldn't be nested, so doesn't matter[tm] - ).with_span(span)?; + let (encoded_array, mut stmts) = self + .postprocess_place_encoding( + base, + ArrayAccessKind::Shared, // shouldn't be nested, so doesn't matter[tm] + ) + .with_span(span)?; let label = self.cfg_method.get_fresh_label_name(); stmts.push(vir::Stmt::label(&label)); - let sequence_types = self.encoder.encode_sequence_types(array_ty).with_span(span)?; + let sequence_types = self + .encoder + .encode_sequence_types(array_ty) + .with_span(span)?; let sequence_len = sequence_types.len(self.encoder, encoded_array.clone()); let array_acc_expr = vir::Expr::predicate_access_predicate( @@ -5636,54 +5901,78 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { ); // exhale and re-inhale to havoc - stmts.push(vir_stmt!{ exhale [array_acc_expr] }); - stmts.push(vir_stmt!{ inhale [array_acc_expr] }); + stmts.push(vir_stmt! { exhale [array_acc_expr] }); + stmts.push(vir_stmt! { inhale [array_acc_expr] }); - let old = |e| { vir::Expr::labelled_old(&label, e) }; + let old = |e| vir::Expr::labelled_old(&label, e); // For sequences with fixed len (e.g. arrays) this will be Some if sequence_types.sequence_len.is_none() { // inhale that len unchanged - let len_eq = vir_expr!{ [ sequence_len ] == [ old(sequence_len.clone()) ] }; - stmts.push(vir_stmt!{ inhale [len_eq] }); + let len_eq = vir_expr! { [ sequence_len ] == [ old(sequence_len.clone()) ] }; + stmts.push(vir_stmt! { inhale [len_eq] }); } - let idx_val_int = self.encoder.patch_snapshots(vir::Expr::snap_app(index)).with_span(span)?; + let idx_val_int = self + .encoder + .patch_snapshots(vir::Expr::snap_app(index)) + .with_span(span)?; // inhale infos about array contents back - let i_var: vir::Expr = vir_local!{ i: Int }.into(); - let zero_le_i = vir_expr!{ [vir::Expr::from(0usize)] <= [ i_var ] }; - let i_lt_len = vir_expr!{ [ i_var ] < [ sequence_len ] }; - let i_ne_idx = vir_expr!{ [ i_var ] != [ old(idx_val_int.clone()) ] }; - let idx_conditions = vir_expr!{ [zero_le_i] && ([i_lt_len] && [i_ne_idx]) }; - let lookup_ret_ty = self.encoder.encode_snapshot_type(sequence_types.elem_ty_rs).with_span(span)?; - let lookup_array_i = sequence_types.encode_lookup_pure_call(self.encoder, encoded_array.clone(), i_var.clone(), lookup_ret_ty.clone()); + let i_var: vir::Expr = vir_local! { i: Int }.into(); + let zero_le_i = vir_expr! { [vir::Expr::from(0usize)] <= [ i_var ] }; + let i_lt_len = vir_expr! { [ i_var ] < [ sequence_len ] }; + let i_ne_idx = vir_expr! { [ i_var ] != [ old(idx_val_int.clone()) ] }; + let idx_conditions = vir_expr! { [zero_le_i] && ([i_lt_len] && [i_ne_idx]) }; + let lookup_ret_ty = self + .encoder + .encode_snapshot_type(sequence_types.elem_ty_rs) + .with_span(span)?; + let lookup_array_i = sequence_types.encode_lookup_pure_call( + self.encoder, + encoded_array.clone(), + i_var.clone(), + lookup_ret_ty.clone(), + ); // FIXME: using `old` here is a work-around for https://github.com/viperproject/prusti-dev/issues/877 // FIXME: which is due to an issue in Silicon, see https://github.com/viperproject/silicon/issues/603 - let lookup_array_i_old = sequence_types.encode_lookup_pure_call(self.encoder, old(encoded_array.clone()), i_var, lookup_ret_ty.clone()); - let lookup_same_as_old = vir_expr!{ [lookup_array_i] == [old(lookup_array_i)] }; - let forall_body = vir_expr!{ [idx_conditions] ==> [lookup_same_as_old] }; - let all_others_unchanged = vir_expr!{ forall i: Int :: { [lookup_array_i_old] } :: [ forall_body ] }; + let lookup_array_i_old = sequence_types.encode_lookup_pure_call( + self.encoder, + old(encoded_array.clone()), + i_var, + lookup_ret_ty.clone(), + ); + let lookup_same_as_old = vir_expr! { [lookup_array_i] == [old(lookup_array_i)] }; + let forall_body = vir_expr! { [idx_conditions] ==> [lookup_same_as_old] }; + let all_others_unchanged = + vir_expr! { forall i: Int :: { [lookup_array_i_old] } :: [ forall_body ] }; - stmts.push(vir_stmt!{ inhale [ all_others_unchanged ]}); + stmts.push(vir_stmt! { inhale [ all_others_unchanged ]}); - let tmp = vir::Expr::from(self.cfg_method.add_fresh_local_var(sequence_types.elem_pred_type.clone())); + let tmp = vir::Expr::from( + self.cfg_method + .add_fresh_local_var(sequence_types.elem_pred_type.clone()), + ); stmts.extend( - self.encode_assign( - tmp.clone(), - rhs, - sequence_types.elem_ty_rs, - location, - ).with_span(span)? + self.encode_assign(tmp.clone(), rhs, sequence_types.elem_ty_rs, location) + .with_span(span)?, ); - let tmp_val_field = self.encoder.encode_value_expr(tmp, sequence_types.elem_ty_rs).with_span(span)?; + let tmp_val_field = self + .encoder + .encode_value_expr(tmp, sequence_types.elem_ty_rs) + .with_span(span)?; - let indexed_lookup_pure_call = sequence_types - .encode_lookup_pure_call(self.encoder, encoded_array, old(idx_val_int), lookup_ret_ty); - let indexed_updated = vir_expr!{ [ indexed_lookup_pure_call ] == [ vir::Expr::snap_app(tmp_val_field) ] }; + let indexed_lookup_pure_call = sequence_types.encode_lookup_pure_call( + self.encoder, + encoded_array, + old(idx_val_int), + lookup_ret_ty, + ); + let indexed_updated = + vir_expr! { [ indexed_lookup_pure_call ] == [ vir::Expr::snap_app(tmp_val_field) ] }; - stmts.push(vir_stmt!{ inhale [ indexed_updated ] }); + stmts.push(vir_stmt! { inhale [ indexed_updated ] }); Ok(stmts) } @@ -5700,7 +5989,8 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { let span = self.mir_encoder.get_span_of_location(location); let stmts = match operand { mir::Operand::Move(place) => { - let (src, mut stmts, ty, _) = self.encode_place(*place, ArrayAccessKind::Shared, location)?; + let (src, mut stmts, ty, _) = + self.encode_place(*place, ArrayAccessKind::Shared, location)?; let encode_stmts = match ty.kind() { ty::TyKind::RawPtr(..) | ty::TyKind::Ref(..) => { // Reborrow. @@ -5710,26 +6000,28 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { field.clone(), location, vir::AssignKind::Move, - false + false, )?; - alloc_stmts.push(vir::Stmt::Assign( vir::Assign { + alloc_stmts.push(vir::Stmt::Assign(vir::Assign { target: lhs.clone().field(field.clone()), source: src.field(field), kind: vir::AssignKind::Move, })); alloc_stmts } - _ if config::enable_purification_optimization() && - prusti_common::vir::optimizations::purification::is_purifiable_type(lhs.get_type()) => { + _ if config::enable_purification_optimization() + && prusti_common::vir::optimizations::purification::is_purifiable_type( + lhs.get_type(), + ) => + { self.encode_copy2(src, lhs.clone(), ty, location)? } _ => { // Just move. - let move_assign = - vir::Stmt::Assign( vir::Assign { - target: lhs.clone(), - source: src, - kind: vir::AssignKind::Move + let move_assign = vir::Stmt::Assign(vir::Assign { + target: lhs.clone(), + source: src, + kind: vir::AssignKind::Move, }); vec![move_assign] } @@ -5747,7 +6039,8 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { } mir::Operand::Copy(place) => { - let (src, mut stmts, ty, _) = self.encode_place(*place, ArrayAccessKind::Shared, location)?; + let (src, mut stmts, ty, _) = + self.encode_place(*place, ArrayAccessKind::Shared, location)?; let encode_stmts = match ty.kind() { ty::TyKind::RawPtr(..) => { return Err(SpannedEncodingError::unsupported( @@ -5763,9 +6056,9 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { ref_field.clone(), location, vir::AssignKind::SharedBorrow(loan.index().into()), - false + false, )?; - stmts.push(vir::Stmt::Assign( vir::Assign { + stmts.push(vir::Stmt::Assign(vir::Assign { target: lhs.clone().field(ref_field.clone()), source: src.field(ref_field), kind: vir::AssignKind::SharedBorrow(loan.index().into()), @@ -5797,17 +6090,18 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { field.clone(), location, vir::AssignKind::Copy, - true + true, )?; // TODO Encoding of string literals is not yet supported, // so do not encode an assignment if the RHS is a string if !is_str(ty) { // Initialize the constant - let const_val = self.encoder + let const_val = self + .encoder .encode_const_expr(ty, expr.literal) .with_span(span)?; // Initialize value of lhs - stmts.push(vir::Stmt::Assign( vir::Assign { + stmts.push(vir::Stmt::Assign(vir::Assign { target: lhs.clone().field(field), source: const_val, kind: vir::AssignKind::Copy, @@ -5838,13 +6132,15 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { location: mir::Location, ) -> SpannedEncodingResult> { let span = self.mir_encoder.get_span_of_location(location); - let encoded_left = self.mir_encoder.encode_operand_expr(left) + let encoded_left = self.mir_encoder.encode_operand_expr(left).with_span(span)?; + let encoded_right = self + .mir_encoder + .encode_operand_expr(right) .with_span(span)?; - let encoded_right = self.mir_encoder.encode_operand_expr(right) + let encoded_value = self + .mir_encoder + .encode_bin_op_expr(op, encoded_left, encoded_right, ty) .with_span(span)?; - let encoded_value = - self.mir_encoder.encode_bin_op_expr(op, encoded_left, encoded_right, ty) - .with_span(span)?; self.encode_copy_value_assign(encoded_lhs, encoded_value, ty, location) } @@ -5857,12 +6153,7 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { ) -> SpannedEncodingResult> { let span = self.mir_encoder.get_span_of_location(location); let field = self.encoder.encode_value_field(ty).with_span(span)?; - self.encode_copy_value_assign2( - encoded_lhs, - encoded_rhs, - field, - location - ) + self.encode_copy_value_assign2(encoded_lhs, encoded_rhs, field, location) } /// Assignment with a(n overflow-)checked binary operation on the RHS. @@ -5883,20 +6174,19 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { } else { unreachable!() }; - let encoded_left = self.mir_encoder.encode_operand_expr(left) + let encoded_left = self.mir_encoder.encode_operand_expr(left).with_span(span)?; + let encoded_right = self + .mir_encoder + .encode_operand_expr(right) + .with_span(span)?; + let encoded_value = self + .mir_encoder + .encode_bin_op_expr(op, encoded_left.clone(), encoded_right.clone(), operand_ty) .with_span(span)?; - let encoded_right = self.mir_encoder.encode_operand_expr(right) + let encoded_check = self + .mir_encoder + .encode_bin_op_check(op, encoded_left, encoded_right, operand_ty) .with_span(span)?; - let encoded_value = self.mir_encoder.encode_bin_op_expr( - op, - encoded_left.clone(), - encoded_right.clone(), - operand_ty, - ).with_span(span)?; - let encoded_check = - self.mir_encoder - .encode_bin_op_check(op, encoded_left, encoded_right, operand_ty) - .with_span(span)?; let field_types = if let ty::TyKind::Tuple(ref x) = ty.kind() { x } else { @@ -5906,19 +6196,25 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { .encoder .encode_raw_ref_field("tuple_0".to_string(), field_types[0]) .with_span(span)?; - let value_field_value = self.encoder.encode_value_field(field_types[0]).with_span(span)?; + let value_field_value = self + .encoder + .encode_value_field(field_types[0]) + .with_span(span)?; let check_field = self .encoder .encode_raw_ref_field("tuple_1".to_string(), field_types[1]) .with_span(span)?; - let check_field_value = self.encoder.encode_value_field(field_types[1]).with_span(span)?; + let check_field_value = self + .encoder + .encode_value_field(field_types[1]) + .with_span(span)?; let mut stmts = if !self .init_info .is_vir_place_accessible(&encoded_lhs, location) { let mut alloc_stmts = self.encode_havoc(&encoded_lhs).with_span(span)?; let mut inhale_acc = |place| { - alloc_stmts.push(vir::Stmt::Inhale( vir::Inhale { + alloc_stmts.push(vir::Stmt::Inhale(vir::Inhale { expr: vir::Expr::acc_permission(place, vir::PermAmount::Write), })); }; @@ -5941,7 +6237,7 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { Vec::with_capacity(2) }; // Initialize lhs.field - stmts.push(vir::Stmt::Assign( vir::Assign { + stmts.push(vir::Stmt::Assign(vir::Assign { target: encoded_lhs .clone() .field(value_field) @@ -5949,7 +6245,7 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { source: encoded_value, kind: vir::AssignKind::Copy, })); - stmts.push(vir::Stmt::Assign( vir::Assign { + stmts.push(vir::Stmt::Assign(vir::Assign { target: encoded_lhs.field(check_field).field(check_field_value), source: encoded_check, kind: vir::AssignKind::Copy, @@ -5969,10 +6265,10 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { ty: ty::Ty<'tcx>, location: mir::Location, ) -> SpannedEncodingResult> { - let encoded_val = self.mir_encoder.encode_operand_expr(operand) - .with_span( - self.mir_encoder.get_span_of_location(location) - )?; + let encoded_val = self + .mir_encoder + .encode_operand_expr(operand) + .with_span(self.mir_encoder.get_span_of_location(location))?; let encoded_value = self.mir_encoder.encode_unary_op_expr(op, encoded_val); // Initialize `lhs.field` self.encode_copy_value_assign(encoded_lhs, encoded_value, ty, location) @@ -5994,10 +6290,12 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { let param_env = tcx.param_env(self.proc_def_id); let layout = match tcx.layout_of(param_env.and(op_ty)) { Ok(layout_of) => layout_of.layout, - Err(_) => return Err(SpannedEncodingError::internal( - format!("could not fetch layout of type `{op_ty}` while translating `{op:?}`"), - self.mir.source_info(location).span, - )), + Err(_) => { + return Err(SpannedEncodingError::internal( + format!("could not fetch layout of type `{op_ty}` while translating `{op:?}`"), + self.mir.source_info(location).span, + )) + } }; let bytes = match op { mir::NullOp::SizeOf => layout.size().bytes(), @@ -6011,12 +6309,7 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { } }; let bytes_vir = vir::Expr::from(bytes); - self.encode_copy_value_assign( - encoded_lhs, - bytes_vir, - ty, - location, - ) + self.encode_copy_value_assign(encoded_lhs, bytes_vir, ty, location) } fn encode_assign_box( @@ -6028,10 +6321,10 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { ) -> SpannedEncodingResult> { assert_eq!(op_ty, ty.boxed_ty()); let span = self.mir_encoder.get_span_of_location(location); - let ref_field = self.encoder.encode_dereference_field(op_ty) - .with_span( - self.mir_encoder.get_span_of_location(location) - )?; + let ref_field = self + .encoder + .encode_dereference_field(op_ty) + .with_span(self.mir_encoder.get_span_of_location(location))?; let box_content = encoded_lhs.clone().field(ref_field.clone()); let mut stmts = self.prepare_assign_target( @@ -6039,14 +6332,17 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { ref_field, location, vir::AssignKind::Move, - false + false, )?; // Allocate `box_content` // TODO: This is also encoding initialization, which should be avoided because both // `Rvalue::NullaryOp(NullOp::Box)` and `Rvalue::ShallowInitBox` don't initialize the // content of the box. - stmts.extend(self.encode_havoc_and_initialization(&box_content).with_span(span)?); + stmts.extend( + self.encode_havoc_and_initialization(&box_content) + .with_span(span)?, + ); // Leave `box_content` uninitialized Ok(stmts) @@ -6063,7 +6359,8 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { ty: ty::Ty<'tcx>, ) -> SpannedEncodingResult> { let span = self.mir_encoder.get_span_of_location(location); - let (encoded_src, mut stmts, src_ty, _) = self.encode_place(src, ArrayAccessKind::Shared, location)?; + let (encoded_src, mut stmts, src_ty, _) = + self.encode_place(src, ArrayAccessKind::Shared, location)?; let encode_stmts = match src_ty.kind() { ty::TyKind::Adt(adt_def, _) if !adt_def.is_box() => { let num_variants = adt_def.variants().len(); @@ -6080,16 +6377,10 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { self.proc_def_id, ); } - let encoded_rhs = self.encoder.encode_discriminant_func_app( - encoded_src, - *adt_def, - )?; - self.encode_copy_value_assign( - encoded_lhs, - encoded_rhs, - ty, - location - )? + let encoded_rhs = self + .encoder + .encode_discriminant_func_app(encoded_src, *adt_def)?; + self.encode_copy_value_assign(encoded_lhs, encoded_rhs, ty, location)? } else { vec![] } @@ -6098,12 +6389,7 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { ty::TyKind::Int(_) | ty::TyKind::Uint(_) | ty::TyKind::Float(_) => { let value_field = self.encoder.encode_value_field(src_ty).with_span(span)?; let discr_value = encoded_src.field(value_field); - self.encode_copy_value_assign( - encoded_lhs, - discr_value, - ty, - location - )? + self.encode_copy_value_assign(encoded_lhs, discr_value, ty, location)? } ref x => { @@ -6129,26 +6415,28 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { let span = self.mir_encoder.get_span_of_location(location); let loan = self.polonius_info().get_loan_at_location(location); let (vir_assign_kind, array_encode_kind) = match mir_borrow_kind { - mir::BorrowKind::Shared => - (vir::AssignKind::SharedBorrow(loan.index().into()), ArrayAccessKind::Shared), - mir::BorrowKind::Mut { .. } => - (vir::AssignKind::MutableBorrow(loan.index().into()), - ArrayAccessKind::Mutable(Some(loan.index().into()), location)), + mir::BorrowKind::Shared => ( + vir::AssignKind::SharedBorrow(loan.index().into()), + ArrayAccessKind::Shared, + ), + mir::BorrowKind::Mut { .. } => ( + vir::AssignKind::MutableBorrow(loan.index().into()), + ArrayAccessKind::Mutable(Some(loan.index().into()), location), + ), _ => return Err(Self::unsupported_borrow_kind(mir_borrow_kind).with_span(span)), }; - let (encoded_value, mut stmts, _, _) = self.encode_place(place, array_encode_kind, location)?; + let (encoded_value, mut stmts, _, _) = + self.encode_place(place, array_encode_kind, location)?; // Initialize ref_var.ref_field let field = self.encoder.encode_value_field(ty).with_span(span)?; - stmts.extend( - self.prepare_assign_target( - encoded_lhs.clone(), - field.clone(), - location, - vir_assign_kind, - false - )? - ); - stmts.push(vir::Stmt::Assign( vir::Assign { + stmts.extend(self.prepare_assign_target( + encoded_lhs.clone(), + field.clone(), + location, + vir_assign_kind, + false, + )?); + stmts.push(vir::Stmt::Assign(vir::Assign { target: encoded_lhs.field(field), source: encoded_value, kind: vir_assign_kind, @@ -6199,24 +6487,33 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { } else { unreachable!("encode_assign_slice on a non-ref?!") }; - let slice_types = self.encoder.encode_sequence_types(*slice_ty).with_span(span)?; + let slice_types = self + .encoder + .encode_sequence_types(*slice_ty) + .with_span(span)?; stmts.extend(self.encode_havoc(&encoded_lhs).with_span(span)?); let val_ref_field = self.encoder.encode_value_field(ty).with_span(span)?; let slice_expr = encoded_lhs.field(val_ref_field); - stmts.push(vir_stmt!{ inhale [vir::Expr::FieldAccessPredicate( vir::FieldAccessPredicate { - base: Box::new(slice_expr.clone()), - permission: vir::PermAmount::Write, - position: vir::Position::default(), - })]}); + stmts.push( + vir_stmt! { inhale [vir::Expr::FieldAccessPredicate( vir::FieldAccessPredicate { + base: Box::new(slice_expr.clone()), + permission: vir::PermAmount::Write, + position: vir::Position::default(), + })]}, + ); - let slice_perm = vir::Expr::PredicateAccessPredicate( vir::PredicateAccessPredicate { + let slice_perm = vir::Expr::PredicateAccessPredicate(vir::PredicateAccessPredicate { predicate_type: slice_types.sequence_pred_type.clone(), argument: Box::new(slice_expr.clone()), - permission: if is_mut { vir::PermAmount::Write } else { vir::PermAmount::Read }, + permission: if is_mut { + vir::PermAmount::Write + } else { + vir::PermAmount::Read + }, position: vir::Position::default(), }); - stmts.push(vir_stmt!{ inhale [slice_perm] }); + stmts.push(vir_stmt! { inhale [slice_perm] }); let (rhs_place, rhs_ty) = if let mir::Operand::Move(place) = operand { let (rhs_place, rhs_ty, ..) = self.mir_encoder.encode_place(*place).with_span(span)?; @@ -6233,7 +6530,10 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { let val_ref_field = self.encoder.encode_value_field(rhs_ty).with_span(span)?; let rhs_expr = rhs_place.field(val_ref_field); - let sequence_types = self.encoder.encode_sequence_types(*rhs_array_ty).with_span(span)?; + let sequence_types = self + .encoder + .encode_sequence_types(*rhs_array_ty) + .with_span(span)?; let slice_len_call = slice_types.len(self.encoder, slice_expr.clone()); @@ -6241,7 +6541,10 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { expr: vir_expr!{ [slice_len_call] == [sequence_types.len(self.encoder, rhs_expr.clone())] } })); - let elem_snap_ty = self.encoder.encode_snapshot_type(sequence_types.elem_ty_rs).with_span(span)?; + let elem_snap_ty = self + .encoder + .encode_snapshot_type(sequence_types.elem_ty_rs) + .with_span(span)?; let i: vir::Expr = vir_local! { i: Int }.into(); @@ -6252,20 +6555,16 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { elem_snap_ty.clone(), ); - let slice_lookup_call = slice_types.encode_lookup_pure_call( - self.encoder, - slice_expr, - i.clone(), - elem_snap_ty, - ); + let slice_lookup_call = + slice_types.encode_lookup_pure_call(self.encoder, slice_expr, i.clone(), elem_snap_ty); let indices = vir_expr! { ([vir::Expr::from(0usize)] <= [i]) && ([i] < [sequence_types.len(self.encoder, rhs_expr)]) }; - stmts.push(vir::Stmt::Inhale( vir::Inhale { + stmts.push(vir::Stmt::Inhale(vir::Inhale { expr: vir_expr! { - forall i: Int :: - { [array_lookup_call] } { [slice_lookup_call] } :: - ([indices] ==> ([array_lookup_call] == [slice_lookup_call])) } + forall i: Int :: + { [array_lookup_call] } { [slice_lookup_call] } :: + ([indices] ==> ([array_lookup_call] == [slice_lookup_call])) }, })); // Store a label for permissions got back from the call @@ -6287,18 +6586,16 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { location: mir::Location, ) -> SpannedEncodingResult> { let span = self.mir_encoder.get_span_of_location(location); - let (encoded_place, mut stmts, place_ty, ..) = self.encode_place( - place, - ArrayAccessKind::Mutable(None, location), - location - )?; + let (encoded_place, mut stmts, place_ty, ..) = + self.encode_place(place, ArrayAccessKind::Mutable(None, location), location)?; match place_ty.kind() { - ty::TyKind::Array(..) | - ty::TyKind::Slice(..) => { - let slice_types = self.encoder.encode_sequence_types(place_ty) - .with_span(span)?; + ty::TyKind::Array(..) | ty::TyKind::Slice(..) => { + let slice_types = self + .encoder + .encode_sequence_types(place_ty) + .with_span(span)?; - stmts.push(vir::Stmt::Assert( vir::Assert { + stmts.push(vir::Stmt::Assert(vir::Assert { expr: vir::Expr::predicate_access_predicate( slice_types.sequence_pred_type.clone(), encoded_place.clone(), @@ -6309,19 +6606,14 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { let rhs = slice_types.len(self.encoder, encoded_place); - stmts.extend( - self.encode_copy_value_assign( - encoded_lhs, - rhs, - dst_ty, - location, - )? - ); - }, - other => return Err( - EncodingError::unsupported(format!("length operation on unsupported type '{other:?}'")) - .with_span(span) - ), + stmts.extend(self.encode_copy_value_assign(encoded_lhs, rhs, dst_ty, location)?); + } + other => { + return Err(EncodingError::unsupported(format!( + "length operation on unsupported type '{other:?}'" + )) + .with_span(span)) + } } Ok(stmts) @@ -6338,11 +6630,21 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { let span = self.mir_encoder.get_span_of_location(location); let sequence_types = self.encoder.encode_sequence_types(ty).with_span(span)?; - let encoded_operand = self.mir_encoder.encode_operand_expr(operand) + let encoded_operand = self + .mir_encoder + .encode_operand_expr(operand) .with_span(span)?; - let len: usize = self.encoder.const_eval_intlike(mir::ConstantKind::Ty(times)).with_span(span)? - .to_u64().unwrap().try_into().unwrap(); - let lookup_ret_ty = self.encoder.encode_snapshot_type(sequence_types.elem_ty_rs) + let len: usize = self + .encoder + .const_eval_intlike(mir::ConstantKind::Ty(times)) + .with_span(span)? + .to_u64() + .unwrap() + .try_into() + .unwrap(); + let lookup_ret_ty = self + .encoder + .encode_snapshot_type(sequence_types.elem_ty_rs) .with_span(span)?; let inhaled_operand = if lookup_ret_ty.is_domain() || lookup_ret_ty.is_snapshot() { @@ -6351,20 +6653,19 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { encoded_operand }; - let mut stmts = self.encode_havoc_and_initialization(&encoded_lhs).with_span(span)?; + let mut stmts = self + .encode_havoc_and_initialization(&encoded_lhs) + .with_span(span)?; let idx: vir::Expr = vir_local! { i: Int }.into(); - let indices = vir_expr! { ([vir::Expr::from(0usize)] <= [idx]) && ([idx] < [vir::Expr::from(len)]) }; - let lookup_pure_call = sequence_types.encode_lookup_pure_call( - self.encoder, - encoded_lhs, - idx, - lookup_ret_ty, - ); - stmts.push(vir::Stmt::Inhale( vir::Inhale { + let indices = + vir_expr! { ([vir::Expr::from(0usize)] <= [idx]) && ([idx] < [vir::Expr::from(len)]) }; + let lookup_pure_call = + sequence_types.encode_lookup_pure_call(self.encoder, encoded_lhs, idx, lookup_ret_ty); + stmts.push(vir::Stmt::Inhale(vir::Inhale { expr: vir_expr! { - forall i: Int :: - { [lookup_pure_call] } :: - ([indices] ==> ([lookup_pure_call] == [inhaled_operand])) } + forall i: Int :: + { [lookup_pure_call] } :: + ([indices] ==> ([lookup_pure_call] == [inhaled_operand])) }, })); Ok(stmts) @@ -6387,8 +6688,12 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { let havoc_ref_method_name = self .encoder .encode_builtin_method_use(BuiltinMethodKind::HavocRef)?; - if let vir::Expr::Local( vir::Local {variable: ref dst_local_var, ..} ) = dst { - Ok(vec![vir::Stmt::MethodCall( vir::MethodCall { + if let vir::Expr::Local(vir::Local { + variable: ref dst_local_var, + .. + }) = dst + { + Ok(vec![vir::Stmt::MethodCall(vir::MethodCall { method_name: havoc_ref_method_name, arguments: vec![], targets: vec![dst_local_var.clone()], @@ -6396,12 +6701,12 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { } else { let tmp_var = self.get_auxiliary_local_var("havoc", dst.get_type().clone()); Ok(vec![ - vir::Stmt::MethodCall( vir::MethodCall { + vir::Stmt::MethodCall(vir::MethodCall { method_name: havoc_ref_method_name, arguments: vec![], targets: vec![tmp_var.clone()], }), - vir::Stmt::Assign( vir::Assign { + vir::Stmt::Assign(vir::Assign { target: dst.clone(), source: tmp_var.into(), kind: vir::AssignKind::Move, @@ -6412,15 +6717,19 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { /// Havoc and assume permission on fields #[tracing::instrument(level = "debug", skip(self))] - fn encode_havoc_and_initialization(&mut self, dst: &vir::Expr) -> EncodingResult> { + fn encode_havoc_and_initialization( + &mut self, + dst: &vir::Expr, + ) -> EncodingResult> { let mut stmts = vec![]; // Havoc `dst` stmts.extend(self.encode_havoc(dst)?); // Initialize `dst` - stmts.push(vir::Stmt::Inhale( vir::Inhale { - expr: self.mir_encoder - .encode_place_predicate_permission(dst.clone(), vir::PermAmount::Write) - .unwrap(), + stmts.push(vir::Stmt::Inhale(vir::Inhale { + expr: self + .mir_encoder + .encode_place_predicate_permission(dst.clone(), vir::PermAmount::Write) + .unwrap(), })); Ok(stmts) } @@ -6435,16 +6744,14 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { field: vir::Field, location: mir::Location, vir_assign_kind: vir::AssignKind, - can_copy_reference: bool // reference copies are allowed if the field is a constant + can_copy_reference: bool, // reference copies are allowed if the field is a constant ) -> SpannedEncodingResult> { let span = self.mir_encoder.get_span_of_location(location); if !self.init_info.is_vir_place_accessible(&dst, location) { let mut alloc_stmts = self.encode_havoc(&dst).with_span(span)?; let dst_field = dst.clone().field(field.clone()); let acc = vir::Expr::acc_permission(dst_field.clone(), vir::PermAmount::Write); - alloc_stmts.push(vir::Stmt::Inhale( vir::Inhale { - expr: acc, - })); + alloc_stmts.push(vir::Stmt::Inhale(vir::Inhale { expr: acc })); match vir_assign_kind { vir::AssignKind::Copy => { if field.typ.is_typed_ref_or_type_var() { @@ -6452,11 +6759,9 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { let pred_acc = vir::Expr::predicate_access_predicate( field.typ, dst_field, - vir::PermAmount::Read + vir::PermAmount::Read, ); - alloc_stmts.push(vir::Stmt::Inhale( - vir::Inhale { expr: pred_acc } - )); + alloc_stmts.push(vir::Stmt::Inhale(vir::Inhale { expr: pred_acc })); } else { // TODO: Inhale the predicate rooted at dst_field return Err(SpannedEncodingError::unsupported( @@ -6492,9 +6797,9 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { field.clone(), location, vir::AssignKind::Copy, - false + false, )?; - stmts.push(vir::Stmt::Assign( vir::Assign { + stmts.push(vir::Stmt::Assign(vir::Assign { target: lhs.field(field), source: rhs, kind: vir::AssignKind::Copy, @@ -6513,12 +6818,7 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { ) -> SpannedEncodingResult> { let span = self.mir_encoder.get_span_of_location(location); let field = self.encoder.encode_value_field(ty).with_span(span)?; - self.encode_copy_value_assign2( - dst, - src.field(field.clone()), - field, - location - ) + self.encode_copy_value_assign2(dst, src.field(field.clone()), field, location) } /// Copy a value by inhaling snapshot equality. @@ -6528,11 +6828,8 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { dst: vir::Expr, ) -> EncodingResult> { let mut stmts = self.encode_havoc_and_initialization(&dst)?; - stmts.push(vir::Stmt::Inhale( vir::Inhale { - expr: vir::Expr::eq_cmp( - vir::Expr::snap_app(src), - vir::Expr::snap_app(dst), - ), + stmts.push(vir::Stmt::Inhale(vir::Inhale { + expr: vir::Expr::eq_cmp(vir::Expr::snap_app(src), vir::Expr::snap_app(dst)), })); Ok(stmts) } @@ -6550,9 +6847,7 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { | ty::TyKind::Int(_) | ty::TyKind::Uint(_) | ty::TyKind::Float(_) - | ty::TyKind::Char => { - self.encode_copy_primitive_value(src, dst, self_ty, location)? - } + | ty::TyKind::Char => self.encode_copy_primitive_value(src, dst, self_ty, location)?, ty::TyKind::Adt(_, _) | ty::TyKind::Closure(_, _) @@ -6564,8 +6859,11 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { _ => { return Err(SpannedEncodingError::unsupported( - format!("copy operation for an unsupported type {:?}", self_ty.kind()), - span + format!( + "copy operation for an unsupported type {:?}", + self_ty.kind() + ), + span, )); } }; @@ -6615,7 +6913,7 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { if adt_def.is_union() { return Err(SpannedEncodingError::unsupported( "unions are not supported", - span + span, )); } let num_variants = adt_def.variants().len(); @@ -6626,10 +6924,7 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { // Handle *signed* discriminats let discr_type = adt_def.repr().discr_type(); let discr_value: vir::Expr = if discr_type.is_signed() { - let bit_size = - Integer::from_attr(&tcx, discr_type) - .size() - .bits(); + let bit_size = Integer::from_attr(&tcx, discr_type).size().bits(); let shift = 128 - bit_size; let unsigned_discr = adt_def.discriminant_for_variant(tcx, variant_index).val; @@ -6646,20 +6941,24 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { let discriminant = self .encoder .encode_discriminant_func_app(dst.clone(), adt_def)?; - stmts.push(vir::Stmt::Inhale( vir::Inhale { + stmts.push(vir::Stmt::Inhale(vir::Inhale { expr: vir::Expr::eq_cmp(discriminant, discr_value), })); let variant_name = variant_def.ident(tcx).to_string(); let new_dst_base = dst_base.variant(&variant_name); - let variant_field = if let vir::Expr::Variant( vir::Variant {variant_index: ref field, ..}) = new_dst_base { + let variant_field = if let vir::Expr::Variant(vir::Variant { + variant_index: ref field, + .. + }) = new_dst_base + { field.clone() } else { unreachable!() }; if !variant_def.fields.is_empty() { - stmts.push(vir::Stmt::Downcast( vir::Downcast { + stmts.push(vir::Stmt::Downcast(vir::Downcast { base: dst.clone(), field: variant_field, })); @@ -6671,7 +6970,8 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { let operand = &operands[field_index.into()]; let field_name = field.ident(tcx).to_string(); let field_ty = field.ty(tcx, subst); - let encoded_field = self.encoder + let encoded_field = self + .encoder .encode_struct_field(&field_name, field_ty) .with_span(span)?; stmts.extend(self.encode_assign_operand( @@ -6684,12 +6984,16 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { mir::AggregateKind::Closure(def_id, substs) => { // TODO: might need to assert history invariants? - assert!(!self.encoder.is_spec_closure(def_id), "spec closure: {def_id:?}"); + assert!( + !self.encoder.is_spec_closure(def_id), + "spec closure: {def_id:?}" + ); let cl_substs = substs.as_closure(); for (field_index, field_ty) in cl_substs.upvar_tys().iter().enumerate() { let operand = &operands[field_index.into()]; let field_name = format!("closure_{field_index}"); - let encoded_field = self.encoder + let encoded_field = self + .encoder .encode_raw_ref_field(field_name, field_ty) .with_span(span)?; stmts.extend(self.encode_assign_operand( @@ -6702,14 +7006,22 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { mir::AggregateKind::Array(..) => { let sequence_types = self.encoder.encode_sequence_types(ty).with_span(span)?; - let lookup_ret_ty = self.encoder.encode_snapshot_type(sequence_types.elem_ty_rs) + let lookup_ret_ty = self + .encoder + .encode_snapshot_type(sequence_types.elem_ty_rs) .with_span(span)?; for (idx, operand) in operands.iter().enumerate() { - let lookup_pure_call = sequence_types - .encode_lookup_pure_call(self.encoder, dst.clone(), idx.into(), lookup_ret_ty.clone()); + let lookup_pure_call = sequence_types.encode_lookup_pure_call( + self.encoder, + dst.clone(), + idx.into(), + lookup_ret_ty.clone(), + ); - let encoded_operand = self.mir_encoder.encode_operand_expr(operand) + let encoded_operand = self + .mir_encoder + .encode_operand_expr(operand) .with_span(span)?; stmts.push( @@ -6723,7 +7035,7 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { mir::AggregateKind::Generator(..) => { return Err(SpannedEncodingError::unsupported( "construction of generators is not supported", - span + span, )); } } @@ -6742,7 +7054,10 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { } #[tracing::instrument(level = "debug", skip(self))] - fn get_label_after_location(&mut self, location: mir::Location) -> SpannedEncodingResult> { + fn get_label_after_location( + &mut self, + location: mir::Location, + ) -> SpannedEncodingResult> { let opt_label = self.label_after_location.get(&location); if opt_label.is_none() { if config::allow_unreachable_unsupported_code() { @@ -6781,9 +7096,12 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { location: mir::Location, ) -> SpannedEncodingResult<(vir::Expr, Vec, ty::Ty<'tcx>, Option)> { let span = self.mir_encoder.get_span_of_location(location); - let (encoded_place, ty, variant_idx) = self.mir_encoder.encode_place(place).with_span(span)?; + let (encoded_place, ty, variant_idx) = + self.mir_encoder.encode_place(place).with_span(span)?; trace!("encode_place(ty={:?})", ty); - let (encoded_expr, encoding_stmts) = self.postprocess_place_encoding(encoded_place, encode_kind).with_span(span)?; + let (encoded_expr, encoding_stmts) = self + .postprocess_place_encoding(encoded_place, encode_kind) + .with_span(span)?; Ok((encoded_expr, encoding_stmts, ty, variant_idx)) } @@ -6796,13 +7114,23 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { ) -> EncodingResult<(vir::Expr, Vec)> { let sequence_types = self.encoder.encode_sequence_types(sequence_ty)?; - let lookup_res: vir::Expr = self.cfg_method.add_fresh_local_var(sequence_types.elem_pred_type.clone()).into(); - let lookup_res_val_field = self.encoder.encode_value_expr(lookup_res.clone(), sequence_types.elem_ty_rs)?; - let snap_lookup_res_val_field = self.encoder.patch_snapshots(vir::Expr::snap_app(lookup_res_val_field))?; + let lookup_res: vir::Expr = self + .cfg_method + .add_fresh_local_var(sequence_types.elem_pred_type.clone()) + .into(); + let lookup_res_val_field = self + .encoder + .encode_value_expr(lookup_res.clone(), sequence_types.elem_ty_rs)?; + let snap_lookup_res_val_field = self + .encoder + .patch_snapshots(vir::Expr::snap_app(lookup_res_val_field))?; - let lookup_ret_ty = self.encoder.encode_snapshot_type(sequence_types.elem_ty_rs)?; + let lookup_ret_ty = self + .encoder + .encode_snapshot_type(sequence_types.elem_ty_rs)?; - let (encoded_base_expr, mut stmts) = self.postprocess_place_encoding(base, ArrayAccessKind::Shared)?; + let (encoded_base_expr, mut stmts) = + self.postprocess_place_encoding(base, ArrayAccessKind::Shared)?; stmts.extend(self.encode_havoc_and_initialization(&lookup_res)?); let idx_val_int = self.encoder.patch_snapshots(vir::Expr::snap_app(index))?; @@ -6814,13 +7142,17 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { lookup_ret_ty, ); - stmts.push(vir::Stmt::Assert( vir::Assert { - expr: vir::Expr::predicate_access_predicate(sequence_types.sequence_pred_type, encoded_base_expr, vir::PermAmount::Read), + stmts.push(vir::Stmt::Assert(vir::Assert { + expr: vir::Expr::predicate_access_predicate( + sequence_types.sequence_pred_type, + encoded_base_expr, + vir::PermAmount::Read, + ), position: vir::Position::default(), })); - stmts.push(vir::Stmt::Inhale( vir::Inhale { - expr: vir_expr!{ [ lookup_pure_call ] == [ snap_lookup_res_val_field ] } + stmts.push(vir::Stmt::Inhale(vir::Inhale { + expr: vir_expr! { [ lookup_pure_call ] == [ snap_lookup_res_val_field ] }, })); Ok((lookup_res, stmts)) } @@ -6835,11 +7167,19 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { ) -> EncodingResult<(vir::Expr, Vec)> { let sequence_types = self.encoder.encode_sequence_types(sequence_ty)?; - let res: vir::Expr = self.cfg_method.add_fresh_local_var(sequence_types.elem_pred_type.clone()).into(); - let res_val_field = self.encoder.encode_value_expr(res.clone(), sequence_types.elem_ty_rs)?; - let snap_res_val_field = self.encoder.patch_snapshots(vir::Expr::snap_app(res_val_field.clone()))?; + let res: vir::Expr = self + .cfg_method + .add_fresh_local_var(sequence_types.elem_pred_type.clone()) + .into(); + let res_val_field = self + .encoder + .encode_value_expr(res.clone(), sequence_types.elem_ty_rs)?; + let snap_res_val_field = self + .encoder + .patch_snapshots(vir::Expr::snap_app(res_val_field.clone()))?; - let (encoded_base_expr, mut stmts) = self.postprocess_place_encoding(base, ArrayAccessKind::Mutable(None, location))?; + let (encoded_base_expr, mut stmts) = + self.postprocess_place_encoding(base, ArrayAccessKind::Mutable(None, location))?; let idx_val_int = self.encoder.patch_snapshots(vir::Expr::snap_app(index))?; @@ -6857,26 +7197,26 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { })); // exhale Array$4$i32(self) - let array_access_pred = vir::Expr::pred_permission( - encoded_base_expr.clone(), - vir::PermAmount::Write, - ).unwrap(); + let array_access_pred = + vir::Expr::pred_permission(encoded_base_expr.clone(), vir::PermAmount::Write).unwrap(); - stmts.push(vir_stmt!{ exhale [array_access_pred] }); + stmts.push(vir_stmt! { exhale [array_access_pred] }); - let old = |e| { vir::Expr::labelled_old(&before_label, e) }; - let old_lhs = |e| { vir::Expr::labelled_old("lhs", e) }; + let old = |e| vir::Expr::labelled_old(&before_label, e); + let old_lhs = |e| vir::Expr::labelled_old("lhs", e); // value of res - let lookup_ret_ty = self.encoder.encode_snapshot_type(sequence_types.elem_ty_rs)?; + let lookup_ret_ty = self + .encoder + .encode_snapshot_type(sequence_types.elem_ty_rs)?; let lookup_pure_call = sequence_types.encode_lookup_pure_call( self.encoder, encoded_base_expr.clone(), idx_val_int.clone(), lookup_ret_ty.clone(), ); - stmts.push(vir::Stmt::Inhale( vir::Inhale { - expr: vir_expr!{ [ old(lookup_pure_call) ] == [ snap_res_val_field ] } + stmts.push(vir::Stmt::Inhale(vir::Inhale { + expr: vir_expr! { [ old(lookup_pure_call) ] == [ snap_res_val_field ] }, })); // inhale magic wand @@ -6893,21 +7233,22 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { // NEEDSWORK: the vir! macro can't do everything we want here.. // TODO: de-duplicate with encode_array_direct_assign - let i_var: vir::Expr = vir_local!{ i: Int }.into(); + let i_var: vir::Expr = vir_local! { i: Int }.into(); - let zero_le_i = vir_expr!{ [ vir::Expr::from(0) ] <= [ i_var ] }; - let i_lt_len = vir_expr!{ [ i_var ] < [ sequence_types.len(self.encoder, encoded_base_expr.clone()) ] }; - let i_ne_idx = vir_expr!{ [ i_var ] != [ old(idx_val_int.clone()) ] }; - let idx_conditions = vir_expr!{ [zero_le_i] && ([i_lt_len] && [i_ne_idx]) }; + let zero_le_i = vir_expr! { [ vir::Expr::from(0) ] <= [ i_var ] }; + let i_lt_len = vir_expr! { [ i_var ] < [ sequence_types.len(self.encoder, encoded_base_expr.clone()) ] }; + let i_ne_idx = vir_expr! { [ i_var ] != [ old(idx_val_int.clone()) ] }; + let idx_conditions = vir_expr! { [zero_le_i] && ([i_lt_len] && [i_ne_idx]) }; let lookup_array_i = sequence_types.encode_lookup_pure_call( self.encoder, encoded_base_expr.clone(), i_var, lookup_ret_ty.clone(), ); - let lookup_same_as_old = vir_expr!{ [lookup_array_i] == [old(lookup_array_i.clone())] }; - let forall_body = vir_expr!{ [idx_conditions] ==> [lookup_same_as_old] }; - let all_others_unchanged = vir_expr!{ forall i: Int :: { [lookup_array_i] } :: [ forall_body ] }; + let lookup_same_as_old = vir_expr! { [lookup_array_i] == [old(lookup_array_i.clone())] }; + let forall_body = vir_expr! { [idx_conditions] ==> [lookup_same_as_old] }; + let all_others_unchanged = + vir_expr! { forall i: Int :: { [lookup_array_i] } :: [ forall_body ] }; let indexed_lookup_pure = sequence_types.encode_lookup_pure_call( self.encoder, encoded_base_expr.clone(), @@ -6915,14 +7256,15 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { lookup_ret_ty, ); // TODO: old inside snapshot or the other way around? - let snap_old_res_val_field = self.encoder.patch_snapshots(vir::Expr::snap_app(res_val_field.clone()))?; - let indexed_updated = vir_expr!{ [ indexed_lookup_pure ] == [ old_lhs(snap_old_res_val_field) ] }; + let snap_old_res_val_field = self + .encoder + .patch_snapshots(vir::Expr::snap_app(res_val_field.clone()))?; + let indexed_updated = + vir_expr! { [ indexed_lookup_pure ] == [ old_lhs(snap_old_res_val_field) ] }; - let magic_wand_rhs = vir_expr!{ [all_others_unchanged] && [indexed_updated] }; - self.array_magic_wand_at.insert( - location, - (res_val_field, encoded_base_expr, magic_wand_rhs) - ); + let magic_wand_rhs = vir_expr! { [all_others_unchanged] && [indexed_updated] }; + self.array_magic_wand_at + .insert(location, (res_val_field, encoded_base_expr, magic_wand_rhs)); Ok((res, stmts)) } @@ -6939,8 +7281,18 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { let (expr, stmts) = self.postprocess_place_encoding(base, array_encode_kind)?; (expr.field(field), stmts) } - PlaceEncoding::SliceAccess { base, index, rust_slice_ty: rust_ty, .. } | - PlaceEncoding::ArrayAccess { base, index, rust_array_ty: rust_ty, .. } => { + PlaceEncoding::SliceAccess { + base, + index, + rust_slice_ty: rust_ty, + .. + } + | PlaceEncoding::ArrayAccess { + base, + index, + rust_array_ty: rust_ty, + .. + } => { if let ArrayAccessKind::Mutable(loan, location) = array_encode_kind { self.encode_sequence_lookup_mut(*base, index, rust_ty, loan, location)? } else { @@ -6949,17 +7301,23 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { } PlaceEncoding::Variant { box base, field } => { let (expr, stmts) = self.postprocess_place_encoding(base, array_encode_kind)?; - (vir::Expr::Variant( vir::Variant { - base: Box::new(expr), - variant_index: field, - position: vir::Position::default(), - }), - stmts) + ( + vir::Expr::Variant(vir::Variant { + base: Box::new(expr), + variant_index: field, + position: vir::Position::default(), + }), + stmts, + ) } }) } - fn register_error + Debug>(&self, span: T, error_ctxt: ErrorCtxt) -> vir::Position { + fn register_error + Debug>( + &self, + span: T, + error_ctxt: ErrorCtxt, + ) -> vir::Position { self.mir_encoder.register_error(span, error_ctxt) } } @@ -6979,17 +7337,19 @@ fn convert_loans_to_borrows(loans: &[facts::Loan]) -> Vec { /// len: Length of borrow_infos fn assert_one_magic_wand(len: usize) -> EncodingResult<()> { if len > 1 { - Err(EncodingError::internal( - format!("We can have at most one magic wand in the postcondition. But we have {len:?}") - )) - } else { Ok(()) } + Err(EncodingError::internal(format!( + "We can have at most one magic wand in the postcondition. But we have {len:?}" + ))) + } else { + Ok(()) + } } // Checks if a type is a reference to a string, or a reference to a reference to a string, etc. fn is_str(ty: ty::Ty<'_>) -> bool { match ty.kind() { ty::TyKind::Ref(_, inner, _) => inner.is_str() || is_str(*inner), - _ => false + _ => false, } } diff --git a/prusti-viper/src/encoder/purifier.rs b/prusti-viper/src/encoder/purifier.rs index 98e3ee91583..2504e3bb016 100644 --- a/prusti-viper/src/encoder/purifier.rs +++ b/prusti-viper/src/encoder/purifier.rs @@ -167,17 +167,11 @@ impl StmtWalker for VarDependencyCollector { let dependencies = collect_variables(source); let dependents = collect_variables(target); for dependent in &dependents { - let entry = self - .dependencies - .entry(dependent.clone()) - .or_default(); + let entry = self.dependencies.entry(dependent.clone()).or_default(); entry.extend(dependencies.iter().cloned()); } for dependency in dependencies { - let entry = self - .dependents - .entry(dependency) - .or_default(); + let entry = self.dependents.entry(dependency).or_default(); entry.extend(dependents.iter().cloned()); } match kind { diff --git a/prusti-viper/src/encoder/stub_function_encoder.rs b/prusti-viper/src/encoder/stub_function_encoder.rs index a552fa2967d..5c5c3270ac9 100644 --- a/prusti-viper/src/encoder/stub_function_encoder.rs +++ b/prusti-viper/src/encoder/stub_function_encoder.rs @@ -4,17 +4,19 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -use crate::encoder::high::generics::HighGenericsEncoderInterface; -use crate::encoder::mir_encoder::{MirEncoder, PlaceEncoder}; -use crate::encoder::Encoder; -use crate::encoder::snapshot::interface::SnapshotEncoderInterface; -use vir_crate::polymorphic as vir; -use prusti_rustc_interface::hir::def_id::DefId; -use prusti_rustc_interface::middle::ty::GenericArgsRef; -use prusti_rustc_interface::middle::mir; +use crate::encoder::{ + errors::{SpannedEncodingResult, WithSpan}, + high::generics::HighGenericsEncoderInterface, + mir_encoder::{MirEncoder, PlaceEncoder}, + snapshot::interface::SnapshotEncoderInterface, + Encoder, +}; use log::debug; -use crate::encoder::errors::WithSpan; -use crate::encoder::errors::SpannedEncodingResult; +use prusti_rustc_interface::{ + hir::def_id::DefId, + middle::{mir, ty::GenericArgsRef}, +}; +use vir_crate::polymorphic as vir; pub struct StubFunctionEncoder<'p, 'v: 'p, 'tcx: 'v> { encoder: &'p Encoder<'v, 'tcx>, @@ -52,13 +54,17 @@ impl<'p, 'v: 'p, 'tcx: 'v> StubFunctionEncoder<'p, 'v, 'tcx> { .map(|local| { let var_name = self.mir_encoder.encode_local_var_name(local); let mir_type = self.mir_encoder.get_local_ty(local); - self.encoder.encode_snapshot_type(mir_type) + self.encoder + .encode_snapshot_type(mir_type) .map(|var_type| vir::LocalVar::new(var_name, var_type)) }) .collect::>() .with_span(self.mir.span)?; - let type_arguments = self.encoder.encode_generic_arguments(self.proc_def_id, self.substs).with_span(self.mir.span)?; + let type_arguments = self + .encoder + .encode_generic_arguments(self.proc_def_id, self.substs) + .with_span(self.mir.span)?; let return_type = self.encode_function_return_type()?; diff --git a/prusti-viper/src/encoder/stub_procedure_encoder.rs b/prusti-viper/src/encoder/stub_procedure_encoder.rs index c2fd09b4b01..92ffe03c214 100644 --- a/prusti-viper/src/encoder/stub_procedure_encoder.rs +++ b/prusti-viper/src/encoder/stub_procedure_encoder.rs @@ -4,20 +4,17 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -use crate::encoder::high::types::HighTypeEncoderInterface; -use crate::encoder::mir_encoder::{MirEncoder, PlaceEncoder}; -use crate::encoder::Encoder; -use prusti_common::vir::ToGraphViz; -use vir_crate::polymorphic::{self as vir, Successor}; -use prusti_common::config; +use crate::encoder::{ + high::types::HighTypeEncoderInterface, + mir_encoder::{MirEncoder, PlaceEncoder}, + Encoder, +}; +use prusti_common::{config, report::log, vir::ToGraphViz}; use prusti_interface::environment::Procedure; -use prusti_common::report::log; -use prusti_rustc_interface::hir::def_id::DefId; -use prusti_rustc_interface::middle::mir; - +use prusti_rustc_interface::{hir::def_id::DefId, middle::mir}; +use vir_crate::polymorphic::{self as vir, Successor}; -pub struct StubProcedureEncoder<'p, 'v: 'p, 'tcx: 'v> - { +pub struct StubProcedureEncoder<'p, 'v: 'p, 'tcx: 'v> { encoder: &'p Encoder<'v, 'tcx>, mir: &'p mir::Body<'tcx>, mir_encoder: MirEncoder<'p, 'v, 'tcx>, @@ -58,7 +55,8 @@ impl<'p, 'v: 'p, 'tcx: 'v> StubProcedureEncoder<'p, 'v, 'tcx> { let name = self.mir_encoder.encode_local_var_name(local); let typ = self .encoder - .encode_type(self.mir_encoder.get_local_ty(local)).unwrap(); // will panic if attempting to encode unsupported type + .encode_type(self.mir_encoder.get_local_ty(local)) + .unwrap(); // will panic if attempting to encode unsupported type cfg_method.add_formal_return(&name, typ) } diff --git a/prusti-viper/src/encoder/versioning/mod.rs b/prusti-viper/src/encoder/versioning/mod.rs index df3a4907143..260ce5c11d2 100644 --- a/prusti-viper/src/encoder/versioning/mod.rs +++ b/prusti-viper/src/encoder/versioning/mod.rs @@ -16,7 +16,7 @@ pub fn bump_mem_version_name() -> &'static str { pub fn bump_mem_version_definition() -> vir::BodylessMethod { vir::BodylessMethod { name: BUMP_MEM_VERSION_NAME.to_string(), - formal_args: vec![vir_local!{ mem: Ref }], + formal_args: vec![vir_local! { mem: Ref }], formal_returns: vec![], pres: vec![], posts: vec![], diff --git a/prusti-viper/src/lib.rs b/prusti-viper/src/lib.rs index 86876199b0c..b51d05a3c55 100644 --- a/prusti-viper/src/lib.rs +++ b/prusti-viper/src/lib.rs @@ -13,7 +13,6 @@ #![feature(extract_if)] #![feature(let_chains)] #![feature(type_changing_struct_update)] - #![deny(unused_must_use)] #![deny(unreachable_patterns)] #![warn(clippy::disallowed_types)] @@ -21,7 +20,6 @@ #![allow(clippy::iter_with_drain)] // We may want to remove this in the future. #![allow(clippy::needless_lifetimes)] - #![allow(clippy::needless_pass_by_ref_mut)] // see https://github.com/rust-lang/rust-clippy/issues/11179 pub mod encoder; diff --git a/prusti-viper/src/utils/mod.rs b/prusti-viper/src/utils/mod.rs index 5789127116a..2c43bdced29 100644 --- a/prusti-viper/src/utils/mod.rs +++ b/prusti-viper/src/utils/mod.rs @@ -6,7 +6,6 @@ use prusti_rustc_interface::middle::ty; - pub mod to_string; pub mod type_visitor; @@ -42,9 +41,10 @@ pub fn ty_to_string(typ: &ty::TyKind) -> String { &ty::TyKind::Placeholder(_) => "placeholder type", &ty::TyKind::Infer(_) => "inference type", &ty::TyKind::Error(_) => "error type", - }).to_string() + }) + .to_string() } pub fn is_reference(base_ty: ty::Ty) -> bool { matches!(base_ty.kind(), ty::TyKind::RawPtr(..) | ty::TyKind::Ref(..)) -} \ No newline at end of file +} diff --git a/prusti-viper/src/utils/type_visitor.rs b/prusti-viper/src/utils/type_visitor.rs index e5983ce21af..9466ce91938 100644 --- a/prusti-viper/src/utils/type_visitor.rs +++ b/prusti-viper/src/utils/type_visitor.rs @@ -4,12 +4,13 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -use prusti_rustc_interface::hir::Mutability; -use prusti_rustc_interface::middle::ty::{ - AdtDef, FieldDef, List, ParamTy, Region, AliasKind, AliasTy, Ty, TyCtxt, - TypeFlags, TyKind, IntTy, UintTy, FloatTy, VariantDef, GenericArgsRef, Const +use prusti_rustc_interface::{ + hir::{def_id::DefId, Mutability}, + middle::ty::{ + AdtDef, AliasKind, AliasTy, Const, FieldDef, FloatTy, GenericArgsRef, IntTy, List, ParamTy, + Region, Ty, TyCtxt, TyKind, TypeFlags, UintTy, VariantDef, + }, }; -use prusti_rustc_interface::hir::def_id::DefId; pub trait TypeVisitor<'tcx>: Sized { type Error; @@ -27,61 +28,26 @@ pub trait TypeVisitor<'tcx>: Sized { #[tracing::instrument(level = "trace", skip(self))] fn visit_sty(&mut self, sty: &TyKind<'tcx>) -> Result<(), Self::Error> { match *sty { - TyKind::Bool => { - self.visit_bool() - } - TyKind::Int(ty) => { - self.visit_int(ty) - } - TyKind::Uint(ty) => { - self.visit_uint(ty) - } - TyKind::Float(ty) => { - self.visit_float(ty) - } - TyKind::Char => { - self.visit_char() - } - TyKind::Adt(adt_def, substs) => { - self.visit_adt(adt_def, substs) - } - TyKind::Ref(region, ty, mutability) => { - self.visit_ref(region, ty, mutability) - } - TyKind::Tuple(types) => { - self.visit_tuple(types) - } - TyKind::RawPtr(ty_and_mutbl) => { - self.visit_raw_ptr(ty_and_mutbl.ty, ty_and_mutbl.mutbl) - } - TyKind::Never => { - self.visit_never() - } - TyKind::Param(param) => { - self.visit_param(param) - } - TyKind::Alias(AliasKind::Projection, alias_ty) => { - self.visit_projection(alias_ty) - } - TyKind::Closure(def_id, substs) => { - self.visit_closure(def_id, substs) - } - TyKind::FnDef(def_id, substs) => { - self.visit_fndef(def_id, substs) - } - TyKind::Array(ty, len) => { - self.visit_array(ty, len) - } - ref x => { - self.visit_unsupported_sty(x) - } + TyKind::Bool => self.visit_bool(), + TyKind::Int(ty) => self.visit_int(ty), + TyKind::Uint(ty) => self.visit_uint(ty), + TyKind::Float(ty) => self.visit_float(ty), + TyKind::Char => self.visit_char(), + TyKind::Adt(adt_def, substs) => self.visit_adt(adt_def, substs), + TyKind::Ref(region, ty, mutability) => self.visit_ref(region, ty, mutability), + TyKind::Tuple(types) => self.visit_tuple(types), + TyKind::RawPtr(ty_and_mutbl) => self.visit_raw_ptr(ty_and_mutbl.ty, ty_and_mutbl.mutbl), + TyKind::Never => self.visit_never(), + TyKind::Param(param) => self.visit_param(param), + TyKind::Alias(AliasKind::Projection, alias_ty) => self.visit_projection(alias_ty), + TyKind::Closure(def_id, substs) => self.visit_closure(def_id, substs), + TyKind::FnDef(def_id, substs) => self.visit_fndef(def_id, substs), + TyKind::Array(ty, len) => self.visit_array(ty, len), + ref x => self.visit_unsupported_sty(x), } } - fn visit_unsupported_sty( - &mut self, - _sty: &TyKind<'tcx> - ) -> Result<(), Self::Error>; + fn visit_unsupported_sty(&mut self, _sty: &TyKind<'tcx>) -> Result<(), Self::Error>; fn visit_flags(&mut self, _flags: TypeFlags) -> Result<(), Self::Error> { Ok(()) @@ -115,10 +81,7 @@ pub trait TypeVisitor<'tcx>: Sized { Ok(()) } - fn visit_projection( - &mut self, - _data: AliasTy<'tcx> - ) -> Result<(), Self::Error> { + fn visit_projection(&mut self, _data: AliasTy<'tcx>) -> Result<(), Self::Error> { Ok(()) } @@ -126,7 +89,7 @@ pub trait TypeVisitor<'tcx>: Sized { fn visit_adt( &mut self, adt_def: AdtDef<'tcx>, - substs: GenericArgsRef<'tcx> + substs: GenericArgsRef<'tcx>, ) -> Result<(), Self::Error> { walk_adt(self, adt_def, substs) } @@ -138,7 +101,7 @@ pub trait TypeVisitor<'tcx>: Sized { idx: prusti_rustc_interface::target::abi::VariantIdx, variant: &VariantDef, substs: GenericArgsRef<'tcx>, - ) -> Result<(), Self::Error> { + ) -> Result<(), Self::Error> { walk_adt_variant(self, variant, substs) } @@ -157,35 +120,24 @@ pub trait TypeVisitor<'tcx>: Sized { &mut self, region: Region<'tcx>, ty: Ty<'tcx>, - mutability: Mutability + mutability: Mutability, ) -> Result<(), Self::Error> { walk_ref(self, region, ty, mutability) } #[allow(dead_code)] #[tracing::instrument(level = "trace", skip(self))] - fn visit_ref_type( - &mut self, - ty: Ty<'tcx>, - mutability: Mutability - ) -> Result<(), Self::Error> { + fn visit_ref_type(&mut self, ty: Ty<'tcx>, mutability: Mutability) -> Result<(), Self::Error> { walk_ref_type(self, ty, mutability) } #[tracing::instrument(level = "trace", skip(self))] - fn visit_tuple( - &mut self, - types: &'tcx List> - ) -> Result<(), Self::Error> { + fn visit_tuple(&mut self, types: &'tcx List>) -> Result<(), Self::Error> { walk_tuple(self, types) } #[tracing::instrument(level = "trace", skip(self))] - fn visit_raw_ptr( - &mut self, - ty: Ty<'tcx>, - mutability: Mutability - ) -> Result<(), Self::Error> { + fn visit_raw_ptr(&mut self, ty: Ty<'tcx>, mutability: Mutability) -> Result<(), Self::Error> { walk_raw_ptr(self, ty, mutability) } @@ -193,7 +145,7 @@ pub trait TypeVisitor<'tcx>: Sized { fn visit_closure( &mut self, def_id: DefId, - substs: GenericArgsRef<'tcx> + substs: GenericArgsRef<'tcx>, ) -> Result<(), Self::Error> { walk_closure(self, def_id, substs) } @@ -202,17 +154,13 @@ pub trait TypeVisitor<'tcx>: Sized { fn visit_fndef( &mut self, def_id: DefId, - substs: GenericArgsRef<'tcx> + substs: GenericArgsRef<'tcx>, ) -> Result<(), Self::Error> { walk_fndef(self, def_id, substs) } #[tracing::instrument(level = "trace", skip(self))] - fn visit_array( - &mut self, - ty: Ty<'tcx>, - len: Const<'tcx>, - ) -> Result<(), Self::Error> { + fn visit_array(&mut self, ty: Ty<'tcx>, len: Const<'tcx>) -> Result<(), Self::Error> { walk_array(self, ty, len) } } @@ -286,14 +234,13 @@ pub fn walk_raw_ptr<'tcx, E, V: TypeVisitor<'tcx, Error = E>>( pub fn walk_closure<'tcx, E, V: TypeVisitor<'tcx, Error = E>>( visitor: &mut V, _def_id: DefId, - substs: GenericArgsRef<'tcx> + substs: GenericArgsRef<'tcx>, ) -> Result<(), E> { let cl_substs = substs.as_closure(); // TODO: when are there bound typevars? can type visitor deal with generics? - let fn_sig = - cl_substs.sig() - .no_bound_vars() - .ok_or_else(|| visitor.unsupported("higher-ranked lifetimes and types are not supported"))?; + let fn_sig = cl_substs.sig().no_bound_vars().ok_or_else(|| { + visitor.unsupported("higher-ranked lifetimes and types are not supported") + })?; for ty in fn_sig.inputs() { visitor.visit_ty(*ty)?; } @@ -303,7 +250,7 @@ pub fn walk_closure<'tcx, E, V: TypeVisitor<'tcx, Error = E>>( pub fn walk_fndef<'tcx, E, V: TypeVisitor<'tcx, Error = E>>( visitor: &mut V, _def_id: DefId, - substs: GenericArgsRef<'tcx> + substs: GenericArgsRef<'tcx>, ) -> Result<(), E> { for ty in substs.types() { visitor.visit_ty(ty)?; diff --git a/prusti-viper/tests/test_caching.rs b/prusti-viper/tests/test_caching.rs index 958b3634a46..479cf062e28 100644 --- a/prusti-viper/tests/test_caching.rs +++ b/prusti-viper/tests/test_caching.rs @@ -4,12 +4,12 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. +use rustc_hash::FxHashMap; use std::{ fs, - path::{PathBuf, Path}, + path::{Path, PathBuf}, process::Command, }; -use rustc_hash::FxHashMap; fn find_executable_path(base_name: &str) -> PathBuf { let target_directory = if cfg!(debug_assertions) { @@ -71,34 +71,55 @@ fn test_prusti_rustc_caching_hash() { .env("PRUSTI_PRINT_HASH", "true") .output() .expect("failed to execute prusti-rustc"); - assert!(out.status.success(), "Failed to compile: {program:?}\n{}", String::from_utf8(out.stderr).unwrap()); + assert!( + out.status.success(), + "Failed to compile: {program:?}\n{}", + String::from_utf8(out.stderr).unwrap() + ); let stdout = String::from_utf8(out.stdout).unwrap(); - let mut hash_lines = stdout.lines() + let mut hash_lines = stdout + .lines() .skip_while(|line| !line.starts_with("Received verification request for: ")); while let Some(l1) = hash_lines.next() { - let mut full_name = l1.strip_prefix("Received verification request for: ").unwrap().to_string(); + let mut full_name = l1 + .strip_prefix("Received verification request for: ") + .unwrap() + .to_string(); full_name.push_str("-Both.vpr"); - full_name = prusti_common::report::log::to_legal_file_name_of_max_length(full_name, 120); + full_name = + prusti_common::report::log::to_legal_file_name_of_max_length(full_name, 120); let mut name = full_name.split(".rs_"); let _filename = name.next().unwrap(); let fn_name = name.next().unwrap(); let l2 = hash_lines.next().unwrap(); - let hash: u64 = l2.strip_prefix("Hash of the request is: ").unwrap().parse().unwrap(); + let hash: u64 = l2 + .strip_prefix("Hash of the request is: ") + .unwrap() + .parse() + .unwrap(); std::fs::rename( format!("log/viper_program/{full_name}"), - format!("log/viper_program/{hash}.vpr") - ).expect("File rename failed!"); - hashes.entry(fn_name.to_string()) - .and_modify(|other| + format!("log/viper_program/{hash}.vpr"), + ) + .expect("File rename failed!"); + hashes + .entry(fn_name.to_string()) + .and_modify(|other| { if hash != *other { - let f1 = std::fs::read_to_string(format!("log/viper_program/{hash}.vpr")).unwrap(); - let f2 = std::fs::read_to_string(format!("log/viper_program/{}.vpr", *other)).unwrap(); + let f1 = std::fs::read_to_string(format!("log/viper_program/{hash}.vpr")) + .unwrap(); + let f2 = + std::fs::read_to_string(format!("log/viper_program/{}.vpr", *other)) + .unwrap(); println!("{}", diffy::create_patch(&f1, &f2)); std::fs::remove_dir_all("log").unwrap(); std::fs::remove_file(program).unwrap(); - panic!("Hash of function \"{}\" differs: {} vs {}", fn_name, hash, *other); + panic!( + "Hash of function \"{}\" differs: {} vs {}", + fn_name, hash, *other + ); } - ) + }) .or_insert(hash); } }; @@ -118,7 +139,10 @@ fn test_prusti_rustc_caching_error() { .arg("--crate-type=lib") .arg(program) .env("RUST_BACKTRACE", "1") - .env("PRUSTI_CACHE_PATH", cache_file.to_string_lossy().to_string()) + .env( + "PRUSTI_CACHE_PATH", + cache_file.to_string_lossy().to_string(), + ) .output() .expect("failed to execute prusti-rustc"); assert!(!out.status.success()); diff --git a/test-crates/src/main.rs b/test-crates/src/main.rs index c8a21a42cc3..dba314f6fed 100644 --- a/test-crates/src/main.rs +++ b/test-crates/src/main.rs @@ -4,6 +4,10 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. +use clap::Parser; +use log::{error, info, warn, LevelFilter}; +use rustwide::{cmd, logging, logging::LogStorage, Crate, Toolchain, Workspace, WorkspaceBuilder}; +use serde::Deserialize; use std::{ env, error::Error, @@ -11,10 +15,6 @@ use std::{ path::{Path, PathBuf}, process::Command, }; -use log::{error, info, warn, LevelFilter}; -use rustwide::{cmd, logging, logging::LogStorage, Crate, Toolchain, Workspace, WorkspaceBuilder}; -use serde::Deserialize; -use clap::Parser; /// How a crate should be tested. All tests use `check_panics=false`, `check_overflows=false` and /// `skip_unsupported_features=true`. @@ -145,17 +145,21 @@ struct Args { shard_index: usize, } -fn attempt_fetch(krate: &Crate, workspace: &Workspace, num_retries: u8) -> Result<(), failure::Error> { +fn attempt_fetch( + krate: &Crate, + workspace: &Workspace, + num_retries: u8, +) -> Result<(), failure::Error> { let mut i = 0; while i < num_retries + 1 { if let Err(err) = krate.fetch(workspace) { warn!("Error fetching crate {}: {}", krate, err); if i == num_retries { // Last attempt failed, return the error - return Err(err) + return Err(err); } } else { - return Ok(()) + return Ok(()); } i += 1; } @@ -231,7 +235,12 @@ fn main() -> Result<(), Box> { .collect::, _>>()? .into_iter() .filter(|record| record.name.contains(&args.filter_crate_name)) - .map(|record| (Crate::crates_io(&record.name, &record.version), record.test_kind)) + .map(|record| { + ( + Crate::crates_io(&record.name, &record.version), + record.test_kind, + ) + }) .collect(); info!("There are {} crates in total.", crates_list.len()); @@ -242,8 +251,11 @@ fn main() -> Result<(), Box> { // List of crates on which Prusti succeed. let mut successful_crates = vec![]; - let shard_crates_list: Vec<&(Crate, TestKind)> = crates_list.iter().skip(args.shard_index) - .step_by(args.num_shards).collect(); + let shard_crates_list: Vec<&(Crate, TestKind)> = crates_list + .iter() + .skip(args.shard_index) + .step_by(args.num_shards) + .collect(); info!( "Iterate over the {} crates of the shard {}/{}...", shard_crates_list.len(), @@ -251,7 +263,13 @@ fn main() -> Result<(), Box> { args.num_shards, ); for (index, (krate, test_kind)) in shard_crates_list.iter().enumerate() { - info!("Crate {}/{}: {}, test kind: {:?}", index, shard_crates_list.len(), krate, test_kind); + info!( + "Crate {}/{}: {}, test kind: {:?}", + index, + shard_crates_list.len(), + krate, + test_kind + ); if let TestKind::Skip = test_kind { info!("Skip crate"); @@ -303,11 +321,7 @@ fn main() -> Result<(), Box> { guest_prusti_home, cmd::MountKind::ReadOnly, ) - .mount( - host_viper_home, - guest_viper_home, - cmd::MountKind::ReadOnly, - ) + .mount(host_viper_home, guest_viper_home, cmd::MountKind::ReadOnly) .mount(host_z3_home, guest_z3_home, cmd::MountKind::ReadOnly) .mount(&host_java_home, &guest_java_home, cmd::MountKind::ReadOnly); for java_policy_path in &host_java_policies { @@ -320,7 +334,8 @@ fn main() -> Result<(), Box> { let verification_status = build_dir.build(&toolchain, krate, sandbox).run(|build| { logging::capture(&storage, || { - let mut command = build.cmd(&cargo_prusti) + let mut command = build + .cmd(&cargo_prusti) .env("RUST_BACKTRACE", "1") .env("PRUSTI_ASSERT_TIMEOUT", "60000") .env("PRUSTI_LOG_DIR", "/tmp/prusti_log") @@ -331,13 +346,14 @@ fn main() -> Result<(), Box> { .env("PRUSTI_SKIP_UNSUPPORTED_FEATURES", "true"); match test_kind { TestKind::NoErrorsWithUnreachableUnsupportedCode => { - command = command.env("PRUSTI_ALLOW_UNREACHABLE_UNSUPPORTED_CODE", "true"); + command = + command.env("PRUSTI_ALLOW_UNREACHABLE_UNSUPPORTED_CODE", "true"); } - TestKind::NoErrors => {}, + TestKind::NoErrors => {} TestKind::NoCrash => { // Report internal errors as warnings command = command.env("PRUSTI_INTERNAL_ERRORS_AS_WARNINGS", "true"); - }, + } TestKind::Skip => { unreachable!(); } @@ -386,7 +402,11 @@ fn main() -> Result<(), Box> { } // Panic - assert!(failed_crates.is_empty(), "Failed to verify {} crates", failed_crates.len()); + assert!( + failed_crates.is_empty(), + "Failed to verify {} crates", + failed_crates.len() + ); Ok(()) } diff --git a/tracing/proc-macro-tracing/src/lib.rs b/tracing/proc-macro-tracing/src/lib.rs index 044b9e8b47c..a7687d87613 100644 --- a/tracing/proc-macro-tracing/src/lib.rs +++ b/tracing/proc-macro-tracing/src/lib.rs @@ -9,7 +9,7 @@ use proc_macro::TokenStream; use proc_macro2::TokenStream as TokenStream2; use quote::quote; -use syn::{ItemFn, ReturnType, token::Paren, Type, TypeParen}; +use syn::{token::Paren, ItemFn, ReturnType, Type, TypeParen}; // Using `tracing::instrument` without this crate (from the vanilla tracing crate) // causes RA to not pick up the return type properly atm - it colours wrong and @@ -21,17 +21,22 @@ pub fn instrument(attr: TokenStream, tokens: TokenStream) -> TokenStream { let (attr, tokens): (TokenStream2, TokenStream2) = (attr.into(), tokens.into()); if let Ok(mut item) = syn::parse2::(tokens.clone()) { if let ReturnType::Type(a, ty) = item.sig.output { - let new_ty = Type::Paren(TypeParen { paren_token: Paren::default(), elem: ty }); + let new_ty = Type::Paren(TypeParen { + paren_token: Paren::default(), + elem: ty, + }); item.sig.output = ReturnType::Type(a, Box::new(new_ty)); } quote! { #[tracing::tracing_instrument(#attr)] #item - }.into() + } + .into() } else { quote! { #[tracing::tracing_instrument(#attr)] #tokens - }.into() + } + .into() } } diff --git a/tracing/src/lib.rs b/tracing/src/lib.rs index e03deef40ed..e9705a3c56b 100644 --- a/tracing/src/lib.rs +++ b/tracing/src/lib.rs @@ -4,5 +4,5 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -pub use tracing::{*, instrument as tracing_instrument}; pub use proc_macro_tracing::instrument; +pub use tracing::{instrument as tracing_instrument, *}; diff --git a/x.py b/x.py index 8dc7ed8c063..951db082581 100755 --- a/x.py +++ b/x.py @@ -34,48 +34,9 @@ dry_run = False -RUSTFMT_CRATES = [ - 'analysis', - 'jni-gen', - 'prusti', - 'prusti-common', - 'prusti-contracts/prusti-contracts', - 'prusti-contracts/prusti-contracts-proc-macros', - 'prusti-contracts/prusti-specs', - 'prusti-contracts/prusti-std', - 'prusti-contracts-build', - 'prusti-interface', - 'prusti-launch', - 'prusti-rustc-interface', - 'prusti-server', - 'prusti-smt-solver', - 'prusti-tests', - 'prusti-utils', - #'prusti-viper', - 'smt-log-analyzer', - #'test-crates', - 'viper', - 'viper-sys', - 'vir', - 'vir-gen', -] - -RUSTFMT_PATHS = [ - 'prusti-common/src/report/mod.rs', - 'prusti-common/src/utils/mod.rs', - 'prusti-common/src/vir/to_viper.rs', - 'prusti-common/src/vir/low_to_viper/mod.rs', - 'prusti-common/src/vir/optimizations/mod.rs', - 'prusti-viper/src/encoder/foldunfold/mod.rs', - 'prusti-viper/src/encoder/mir/mod.rs', - 'prusti-viper/src/encoder/high/mod.rs', - 'prusti-viper/src/encoder/typed/mod.rs', - 'prusti-viper/src/encoder/middle/mod.rs', - 'prusti-viper/src/encoder/snapshot/mod.rs', - 'prusti-viper/src/encoder/lifetimes/mod.rs', - 'prusti-viper/src/encoder/definition_collector.rs', - 'prusti-viper/src/encoder/counterexamples/mod.rs', - 'vir/defs/mod.rs', +PRUSTI_WORKSPACES = [ + '.', + 'prusti-contracts', ] @@ -208,33 +169,23 @@ def run_viper_server(port=None): run_command(command) -def clippy_in(cwd): - """Run cargo clippy in given subproject.""" - run_command(['cargo', 'clippy', '--', '-D', 'warnings'], cwd=cwd) +def clippy_all(): + """Run clippy in all workspaces.""" + for workspace_path in PRUSTI_WORKSPACES: + run_command(['cargo', 'clippy', '--', '-D', 'warnings'], cwd=workspace_path) -def fmt_in(cwd): - """Run cargo fmt in given subproject.""" - run_command(['cargo', 'fmt'], cwd=cwd) def fmt_all(): - """Run rustfmt on all formatted files.""" - for crate in RUSTFMT_CRATES: - fmt_in(crate) - for path in RUSTFMT_PATHS: - for file in glob.glob(path, recursive=True): - run_command(['rustfmt', file]) + """Run rustfmt in all workspaces.""" + for workspace_path in PRUSTI_WORKSPACES: + run_command(['cargo', 'fmt', '--all'], cwd=workspace_path) -def fmt_check_in(cwd): - """Run cargo fmt check in the given subproject.""" - run_command(['cargo', 'fmt', '--', '--check'], cwd=cwd) def fmt_check_all(): - """Run rustfmt check on all formatted files.""" - for crate in RUSTFMT_CRATES: - fmt_check_in(crate) - for path in RUSTFMT_PATHS: - for file in glob.glob(path, recursive=True): - run_command(['rustfmt', '--check', file]) + """Run rustfmt check in all workspaces.""" + for workspace_path in PRUSTI_WORKSPACES: + run_command(['cargo', 'fmt', '--all', '--', '--check'], cwd=workspace_path) + def check_smir(): """Check that `extern crate` is used only in `prusti_rustc_interface` (TODO: `prusti_interface` is also ignored for now).""" @@ -258,6 +209,7 @@ def check_smir(): ) ) + def package(mode: str, package_path: str): """Packages Prusti artifacts in the `package_path` folder. @@ -359,6 +311,11 @@ def test_package(package_path: str): def main(argv): logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.DEBUG) + + # Check the working directory, because this script uses a lot of relative paths. + if os.path.abspath(os.getcwd()) != os.path.abspath(os.path.dirname(__file__)): + error(f'Please run this script from the root folder of the repository.') + for i, arg in enumerate(argv): if arg.startswith('+'): if arg == '+v' or arg == '++verbose': @@ -385,30 +342,30 @@ def main(argv): elif arg == 'exec': run_command(argv[i+1:]) break - elif arg == 'clippy-in': - clippy_in(*argv[i+1:]) - break - elif arg == 'fmt-check': - fmt_check_in(*argv[i+1:]) + # Run `cargo clippy --all` in all workspaces. + elif arg == 'clippy-all': + clippy_all() break + # Check `cargo fmt --all` in all workspaces. elif arg == 'fmt-check-all': - fmt_check_all(*argv[i+1:]) - break - elif arg == 'fmt': - fmt_in(*argv[i+1:]) - break - elif arg == 'fmt-all': - fmt_all(*argv[i+1:]) + fmt_check_all() break elif arg == 'check-smir': check_smir(*argv[i+1:]) break + # Run `cargo fmt --all` in all workspaces. + elif arg == 'fmt-all': + fmt_all() + break + # Packages Prusti artifacts in the given folder. elif arg == 'package': package(*argv[i+1:]) break + # Quickly test that a Prusti release has been packaged correctly in the given folder. elif arg == 'test-package': test_package(*argv[i+1:]) break + # Run whatever is left as a cargo command. else: cargo(argv[i:]) break