Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 16702d5

Browse files
Aurel300fpoli
authored andcommittedFeb 28, 2023
support unevaluated constants in specs (fix #1268)
1 parent e4896c0 commit 16702d5

File tree

4 files changed

+86
-6
lines changed

4 files changed

+86
-6
lines changed
 
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
use prusti_contracts::*;
2+
3+
enum TestEnum {
4+
Nil,
5+
}
6+
7+
#[ensures(TestEnum::Nil === TestEnum::Nil)]
8+
fn test() {}
9+
10+
fn main() {
11+
let foo = 5;
12+
prusti_assert!(foo === 5);
13+
}

‎prusti-viper/src/encoder/mir/pure/interpreter/interpreter_poly.rs

+6-3
Original file line numberDiff line numberDiff line change
@@ -134,9 +134,12 @@ impl<'p, 'v: 'p, 'tcx: 'v> PureFunctionBackwardInterpreter<'p, 'v, 'tcx> {
134134
&mir::Operand::Move(place) | &mir::Operand::Copy(place) => {
135135
Ok((self.encode_place(place)?.0, false))
136136
}
137-
mir::Operand::Constant(constant) => {
138-
Ok((self.encoder.encode_snapshot_constant(constant)?, true))
139-
}
137+
mir::Operand::Constant(constant) => match constant.literal {
138+
mir::ConstantKind::Unevaluated(c, _cty) => {
139+
Ok((self.encoder.encode_uneval_const(c)?, true))
140+
}
141+
_ => Ok((self.encoder.encode_snapshot_constant(constant)?, true)),
142+
},
140143
}
141144
}
142145

‎prusti-viper/src/encoder/mir/pure/pure_functions/encoder_poly.rs

+49-2
Original file line numberDiff line numberDiff line change
@@ -67,18 +67,65 @@ pub(super) fn encode_body<'p, 'v: 'p, 'tcx: 'v>(
6767
.env()
6868
.body
6969
.get_expression_body(proc_def_id, substs, parent_def_id);
70-
let interpreter = PureFunctionBackwardInterpreter::new(
70+
encode_mir(
7171
encoder,
7272
&mir,
7373
proc_def_id,
7474
pure_encoding_context,
7575
parent_def_id,
76+
)
77+
}
78+
79+
/// Used to encode unevaluated constants.
80+
pub(super) fn encode_promoted<'p, 'v: 'p, 'tcx: 'v>(
81+
encoder: &'p Encoder<'v, 'tcx>,
82+
proc_def_id: ty::WithOptConstParam<DefId>,
83+
promoted_id: mir::Promoted,
84+
parent_def_id: DefId,
85+
substs: SubstsRef<'tcx>,
86+
) -> SpannedEncodingResult<vir::Expr> {
87+
let tcx = encoder.env().tcx();
88+
let promoted_bodies = tcx.promoted_mir_opt_const_arg(proc_def_id);
89+
let param_env = tcx.param_env(parent_def_id);
90+
let mir = tcx.subst_and_normalize_erasing_regions(
91+
substs,
92+
param_env,
93+
promoted_bodies[promoted_id].clone(),
94+
);
95+
encode_mir(
96+
encoder,
97+
&mir,
98+
proc_def_id.did,
99+
PureEncodingContext::Code,
100+
parent_def_id,
101+
)
102+
}
103+
104+
/// Backing implementation for `encode_body` and `encode_promoted`. The extra
105+
/// `mir` argument may be the MIR body identified by `proc_def_id` (when
106+
/// encoding a regular function), or it may be the body of a promoted constant
107+
/// (when encoding an unevaluated constant in the MIR). The latter does not
108+
/// have a `DefId` of its own, it is identified by the `DefId` of its
109+
/// containing function and a promoted ID.
110+
fn encode_mir<'p, 'v: 'p, 'tcx: 'v>(
111+
encoder: &'p Encoder<'v, 'tcx>,
112+
mir: &mir::Body<'tcx>,
113+
proc_def_id: DefId,
114+
pure_encoding_context: PureEncodingContext,
115+
parent_def_id: DefId,
116+
) -> SpannedEncodingResult<vir::Expr> {
117+
let interpreter = PureFunctionBackwardInterpreter::new(
118+
encoder,
119+
mir,
120+
proc_def_id,
121+
pure_encoding_context,
122+
parent_def_id,
76123
);
77124

78125
let function_name = encoder.env().name.get_absolute_item_name(proc_def_id);
79126
debug!("Encode body of pure function {}", function_name);
80127

81-
let state = run_backward_interpretation(&mir, &interpreter)?
128+
let state = run_backward_interpretation(mir, &interpreter)?
82129
.unwrap_or_else(|| panic!("Procedure {proc_def_id:?} contains a loop"));
83130
let body_expr = state.into_expr().unwrap();
84131
debug!(

‎prusti-viper/src/encoder/mir/pure/pure_functions/interface.rs

+18-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use crate::encoder::{
1010
use log::{debug, trace};
1111
use prusti_common::config;
1212
use prusti_interface::data::ProcedureDefId;
13-
use prusti_rustc_interface::middle::{ty, ty::subst::SubstsRef};
13+
use prusti_rustc_interface::middle::{mir, ty, ty::subst::SubstsRef};
1414
use rustc_hash::{FxHashMap, FxHashSet};
1515

1616
use prusti_interface::specs::typed::ProcedureSpecificationKind;
@@ -123,6 +123,11 @@ pub(crate) struct FunctionDescription<'tcx> {
123123
}
124124

125125
pub(crate) trait PureFunctionEncoderInterface<'v, 'tcx> {
126+
fn encode_uneval_const(
127+
&self,
128+
c: mir::UnevaluatedConst<'tcx>,
129+
) -> SpannedEncodingResult<vir_poly::Expr>;
130+
126131
fn encode_pure_expression(
127132
&self,
128133
proc_def_id: ProcedureDefId,
@@ -239,6 +244,18 @@ impl<'v, 'tcx: 'v> PureFunctionEncoderInterface<'v, 'tcx>
239244
Ok(self.pure_function_encoder_state.bodies_high.borrow()[&key].clone())
240245
}
241246

247+
fn encode_uneval_const(
248+
&self,
249+
mir::UnevaluatedConst {
250+
def,
251+
substs,
252+
promoted,
253+
}: mir::UnevaluatedConst<'tcx>,
254+
) -> SpannedEncodingResult<vir_poly::Expr> {
255+
let promoted_id = promoted.expect("unevaluated const should have a promoted ID");
256+
super::encoder_poly::encode_promoted(self, def, promoted_id, def.did, substs)
257+
}
258+
242259
// FIXME: This should be refactored to depend on encode_pure_expression_high
243260
// and moved to prusti-viper/src/encoder/high/pure_functions/interface.rs
244261
fn encode_pure_expression(

0 commit comments

Comments
 (0)
Please sign in to comment.