1use rustc_middle::mir::Local;
8use rustc_middle::ty::{Region, Ty};
9
10#[derive(Clone, Debug, PartialEq)]
13pub(crate) enum PlaceBase {
14 Return,
16 Arg(usize),
18 Local(usize),
20}
21
22impl PlaceBase {
23 pub(crate) fn to_local(&self) -> Local {
25 match self {
26 PlaceBase::Return => Local::from_usize(0),
27 PlaceBase::Arg(n) => Local::from_usize(*n + 1),
28 PlaceBase::Local(n) => Local::from_usize(*n),
29 }
30 }
31
32 pub(crate) fn try_to_local(&self) -> Option<Local> {
36 match self {
37 PlaceBase::Return => None,
38 PlaceBase::Arg(n) => Some(Local::from_usize(*n + 1)),
39 PlaceBase::Local(n) => Some(Local::from_usize(*n)),
40 }
41 }
42}
43
44#[derive(Clone, Debug)]
47pub(crate) enum ContractProjection<'tcx> {
48 Field { index: usize, ty: Option<Ty<'tcx>> },
50 Downcast { variant_index: usize },
52 ForEach,
54}
55
56#[derive(Clone, Debug)]
59pub(crate) struct ContractPlace<'tcx> {
60 pub base: PlaceBase,
62 pub projections: Vec<ContractProjection<'tcx>>,
64}
65
66impl<'tcx> ContractPlace<'tcx> {
67 pub(crate) fn local(base: usize, fields: Vec<(usize, Ty<'tcx>)>) -> Self {
68 Self {
69 base: if base == 0 {
70 PlaceBase::Return
71 } else {
72 PlaceBase::Local(base)
73 },
74 projections: fields
75 .into_iter()
76 .map(|(index, ty)| ContractProjection::Field {
77 index,
78 ty: Some(ty),
79 })
80 .collect(),
81 }
82 }
83
84 pub(crate) fn arg(index: usize) -> Self {
85 Self {
86 base: PlaceBase::Arg(index),
87 projections: Vec::new(),
88 }
89 }
90
91 pub(crate) fn local_base(&self) -> Option<usize> {
92 match self.base {
93 PlaceBase::Return => Some(0),
94 PlaceBase::Local(local) => Some(local),
95 PlaceBase::Arg(_) => None,
96 }
97 }
98
99 pub(crate) fn plain_field_path(&self) -> Option<Vec<usize>> {
103 let mut path = Vec::new();
104 for proj in &self.projections {
105 match proj {
106 ContractProjection::Field { index, .. } => path.push(*index),
107 _ => return None,
108 }
109 }
110 Some(path)
111 }
112}
113
114#[derive(Clone, Copy, Debug)]
115pub(crate) enum NumericBinOp {
116 Add,
117 Sub,
118 Mul,
119 Div,
120 Rem,
121 Min,
122 Max,
123 BitAnd,
124 BitOr,
125 BitXor,
126}
127
128#[derive(Clone, Copy, Debug)]
129pub(crate) enum NumericUnaryOp {
130 Not,
131 Neg,
132}
133
134#[derive(Clone, Debug)]
135pub(crate) enum ContractExpr<'tcx> {
136 Place(ContractPlace<'tcx>),
137 Const(u128),
138 ConstParam {
139 index: u32,
140 name: String,
141 },
142 SizeOf(Ty<'tcx>),
143 AlignOf(Ty<'tcx>),
144 Len(Box<ContractExpr<'tcx>>),
145 IndexAccess {
146 slice: Box<ContractExpr<'tcx>>,
147 index: Box<ContractExpr<'tcx>>,
148 },
149 Binary {
150 op: NumericBinOp,
151 lhs: Box<ContractExpr<'tcx>>,
152 rhs: Box<ContractExpr<'tcx>>,
153 },
154 Unary {
155 op: NumericUnaryOp,
156 expr: Box<ContractExpr<'tcx>>,
157 },
158 If {
159 cond: Box<NumericPredicate<'tcx>>,
160 then_expr: Box<ContractExpr<'tcx>>,
161 else_expr: Box<ContractExpr<'tcx>>,
162 },
163 Unknown,
164}
165
166impl<'tcx> ContractExpr<'tcx> {
167 pub(crate) fn new_value(value: usize) -> Self {
168 Self::Const(value as u128)
169 }
170}
171
172#[derive(Clone, Copy, Debug)]
173pub(crate) enum RelOp {
174 Eq,
175 Ne,
176 Lt,
177 Le,
178 Gt,
179 Ge,
180}
181
182#[derive(Clone, Debug)]
183pub(crate) struct NumericPredicate<'tcx> {
184 pub lhs: ContractExpr<'tcx>,
185 pub op: RelOp,
186 pub rhs: ContractExpr<'tcx>,
187}
188
189impl<'tcx> NumericPredicate<'tcx> {
190 pub(crate) fn new(lhs: ContractExpr<'tcx>, op: RelOp, rhs: ContractExpr<'tcx>) -> Self {
191 Self { lhs, op, rhs }
192 }
193}
194
195#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
206pub(crate) enum PropertyKind {
207 Align,
208 Size,
209 NoPadding,
210 NonNull,
211 Allocated,
212 InBound,
213 NonOverlap,
214 ValidNum,
215 ValidString,
216 ValidCStr,
217 Init,
218 Unwrap,
219 Typed,
220 Owning,
221 Alias,
222 Alive,
223 Pinned,
224 NonVolatile,
225 Opened,
226 Null,
227 Trait,
228 Unreachable,
229 ValidTransmute,
230 SplitTransmute,
231 ContainNoType,
232 NoRawPtr,
233 NoInternalMut,
234 UniInternalMut,
235 AtomicUpdate,
236 RefSend,
237 Unknown,
238}
239
240#[derive(Clone, Debug)]
242pub(crate) enum PropertyArg<'tcx> {
243 Ty(Ty<'tcx>),
245 Expr(ContractExpr<'tcx>),
247 Predicates(Vec<NumericPredicate<'tcx>>),
249 Ident(String),
251 Region(Region<'tcx>),
254}
255
256#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
257pub(crate) enum ContractKind {
258 Precond,
259 Hazard,
260 Option_,
261}
262
263#[derive(Clone, Debug)]
268pub(crate) struct ContractOrigin {
269 pub name: String,
270 pub args: Vec<String>,
271 pub meaning: Option<String>,
272}
273
274#[derive(Clone, Debug)]
281pub(crate) enum Property<'tcx> {
282 Atom(AtomProperty<'tcx>),
283 And(AndProperty<'tcx>),
284 Or(OrProperty<'tcx>),
285}
286
287#[derive(Clone, Debug)]
288pub(crate) struct AtomProperty<'tcx> {
289 pub kind: PropertyKind,
290 pub args: Vec<PropertyArg<'tcx>>,
291 pub contract_kind: ContractKind,
292 pub for_each: Option<ContractPlace<'tcx>>,
297 pub origin: Option<ContractOrigin>,
299}
300
301#[derive(Clone, Debug)]
303pub(crate) struct AndProperty<'tcx> {
304 pub conjuncts: Vec<Box<Property<'tcx>>>,
305 pub contract_kind: ContractKind,
306 pub origin: Option<ContractOrigin>,
308}
309
310#[derive(Clone, Debug)]
312pub(crate) struct OrProperty<'tcx> {
313 pub disjuncts: Vec<Box<Property<'tcx>>>,
314 pub contract_kind: ContractKind,
315 pub origin: Option<ContractOrigin>,
317}
318
319impl<'tcx> Property<'tcx> {
320 pub(crate) fn new_atom(kind: PropertyKind, args: Vec<PropertyArg<'tcx>>) -> Self {
322 Self::Atom(AtomProperty {
323 kind,
324 args,
325 contract_kind: ContractKind::Precond,
326 for_each: None,
327 origin: None,
328 })
329 }
330
331 pub(crate) fn new_and(conjuncts: Vec<Property<'tcx>>) -> Self {
333 Self::And(AndProperty {
334 conjuncts: conjuncts.into_iter().map(Box::new).collect(),
335 contract_kind: ContractKind::Precond,
336 origin: None,
337 })
338 }
339
340 pub(crate) fn new_or(disjuncts: Vec<Property<'tcx>>) -> Self {
342 Self::Or(OrProperty {
343 disjuncts: disjuncts.into_iter().map(Box::new).collect(),
344 contract_kind: ContractKind::Precond,
345 origin: None,
346 })
347 }
348
349 pub(crate) fn conjunction(conjuncts: Vec<Property<'tcx>>) -> Self {
352 if conjuncts.len() == 1 {
353 conjuncts.into_iter().next().unwrap()
354 } else {
355 Self::new_and(conjuncts)
356 }
357 }
358
359 pub(crate) fn kind(&self) -> Option<PropertyKind> {
362 match self {
363 Property::Atom(a) => Some(a.kind),
364 Property::And(_) | Property::Or(_) => None,
365 }
366 }
367
368 pub(crate) fn args(&self) -> &[PropertyArg<'tcx>] {
370 match self {
371 Property::Atom(a) => &a.args,
372 Property::And(_) | Property::Or(_) => &[],
373 }
374 }
375
376 pub(crate) fn target_place(&self) -> Option<&ContractPlace<'tcx>> {
379 match self.args().first()? {
380 PropertyArg::Expr(ContractExpr::Place(cp)) => Some(cp),
381 PropertyArg::Expr(ContractExpr::IndexAccess { slice, .. }) => match slice.as_ref() {
382 ContractExpr::Place(cp) => Some(cp),
383 _ => None,
384 },
385 _ => None,
386 }
387 }
388
389 pub(crate) fn conjuncts(&self) -> &[Box<Property<'tcx>>] {
391 match self {
392 Property::And(a) => &a.conjuncts,
393 Property::Atom(_) | Property::Or(_) => &[],
394 }
395 }
396
397 pub(crate) fn disjuncts(&self) -> &[Box<Property<'tcx>>] {
399 match self {
400 Property::Or(o) => &o.disjuncts,
401 Property::Atom(_) | Property::And(_) => &[],
402 }
403 }
404
405 pub(crate) fn contract_kind(&self) -> ContractKind {
406 match self {
407 Property::Atom(a) => a.contract_kind,
408 Property::And(a) => a.contract_kind,
409 Property::Or(o) => o.contract_kind,
410 }
411 }
412
413 pub(crate) fn for_each(&self) -> Option<&ContractPlace<'tcx>> {
414 match self {
415 Property::Atom(a) => a.for_each.as_ref(),
416 Property::And(_) | Property::Or(_) => None,
417 }
418 }
419
420 pub(crate) fn origin(&self) -> Option<&ContractOrigin> {
422 match self {
423 Property::Atom(a) => a.origin.as_ref(),
424 Property::And(a) => a.origin.as_ref(),
425 Property::Or(o) => o.origin.as_ref(),
426 }
427 }
428
429 pub(crate) fn is_or(&self) -> bool {
430 matches!(self, Property::Or(_))
431 }
432
433 pub(crate) fn is_and(&self) -> bool {
434 matches!(self, Property::And(_))
435 }
436
437 pub(crate) fn apply_kind(&mut self, kind: Option<&str>) {
439 let target = match self {
440 Property::Atom(a) => &mut a.contract_kind,
441 Property::And(a) => &mut a.contract_kind,
442 Property::Or(o) => &mut o.contract_kind,
443 };
444 match kind {
445 Some("hazard") => *target = ContractKind::Hazard,
446 Some("option") => *target = ContractKind::Option_,
447 _ => {}
448 }
449 }
450
451 pub(crate) fn set_origin(&mut self, name: String, args: Vec<String>, meaning: Option<String>) {
454 let origin = ContractOrigin {
455 name,
456 args,
457 meaning,
458 };
459 match self {
460 Property::Atom(a) => a.origin = Some(origin),
461 Property::And(a) => a.origin = Some(origin),
462 Property::Or(o) => o.origin = Some(origin),
463 }
464 }
465
466 pub(crate) fn clear_origin(&mut self) {
468 match self {
469 Property::Atom(a) => a.origin = None,
470 Property::And(a) => a.origin = None,
471 Property::Or(o) => o.origin = None,
472 }
473 }
474
475 pub(crate) fn set_for_each(&mut self, place: Option<ContractPlace<'tcx>>) {
477 if let Property::Atom(a) = self {
478 a.for_each = place;
479 }
480 }
481
482 pub(crate) fn set_contract_kind(&mut self, k: ContractKind) {
484 match self {
485 Property::Atom(a) => a.contract_kind = k,
486 Property::And(a) => a.contract_kind = k,
487 Property::Or(o) => o.contract_kind = k,
488 }
489 }
490}