1use std::{fmt, hash::Hash, iter, ops::ControlFlow, sync::OnceLock};
2
3use flux_arc_interner::{Interned, List, impl_internable, impl_slice_internable};
4use flux_common::{bug, dbg::as_subscript};
5use flux_macros::{TypeFoldable, TypeVisitable};
6use flux_rustc_bridge::{
7 ToRustc,
8 const_eval::{scalar_to_bits, scalar_to_int, scalar_to_uint},
9 ty::{Const, ConstKind, ValTree, VariantIdx},
10};
11use flux_syntax::symbols::sym;
12use itertools::Itertools;
13use liquid_fixpoint::ThyFunc;
14use rustc_abi::{FIRST_VARIANT, FieldIdx};
15use rustc_data_structures::{snapshot_map::SnapshotMap, unord::UnordMap};
16use rustc_hir::def_id::DefId;
17use rustc_index::newtype_index;
18use rustc_macros::{Decodable, Encodable, TyDecodable, TyEncodable};
19use rustc_middle::{
20 mir::Local,
21 ty::{ParamConst, ScalarInt, TyCtxt},
22};
23use rustc_span::{Span, Symbol};
24use rustc_type_ir::{BoundVar, DebruijnIndex, INNERMOST};
25
26use super::{
27 BaseTy, Binder, BoundReftKind, BoundVariableKinds, FuncSort, GenericArgs, GenericArgsExt as _,
28 IntTy, Sort, UintTy,
29};
30use crate::{
31 big_int::BigInt,
32 def_id::FluxDefId,
33 fhir::{self},
34 global_env::GlobalEnv,
35 pretty::*,
36 queries::QueryResult,
37 rty::{
38 BoundVariableKind, SortArg, SortCtor, SubsetTyCtor,
39 fold::{
40 TypeFoldable, TypeFolder, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable,
41 TypeVisitor,
42 },
43 },
44};
45
46#[derive(Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, TypeVisitable, TypeFoldable)]
49pub struct Lambda {
50 body: Binder<Expr>,
51 output: Sort,
52}
53
54impl Lambda {
55 pub fn bind_with_vars(body: Expr, inputs: BoundVariableKinds, output: Sort) -> Self {
56 debug_assert!(inputs.iter().all(BoundVariableKind::is_refine));
57 Self { body: Binder::bind_with_vars(body, inputs), output }
58 }
59
60 pub fn bind_with_fsort(body: Expr, fsort: FuncSort) -> Self {
61 Self { body: Binder::bind_with_sorts(body, fsort.inputs()), output: fsort.output().clone() }
62 }
63
64 pub fn apply(&self, args: &[Expr]) -> Expr {
65 self.body.replace_bound_refts(args)
66 }
67
68 pub fn vars(&self) -> &BoundVariableKinds {
69 self.body.vars()
70 }
71
72 pub fn output(&self) -> Sort {
73 self.output.clone()
74 }
75
76 pub fn fsort(&self) -> FuncSort {
77 let inputs_and_output = self
78 .vars()
79 .iter()
80 .map(|kind| kind.expect_sort().clone())
81 .chain(iter::once(self.output()))
82 .collect();
83 FuncSort { inputs_and_output }
84 }
85}
86
87#[derive(Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, TypeVisitable, TypeFoldable)]
88pub struct AliasReft {
89 pub assoc_id: FluxDefId,
91 pub args: GenericArgs,
92}
93
94impl AliasReft {
95 pub fn self_ty(&self) -> SubsetTyCtor {
96 self.args[0].expect_base().clone()
97 }
98
99 pub fn to_rustc_trait_ref<'tcx>(&self, tcx: TyCtxt<'tcx>) -> rustc_middle::ty::TraitRef<'tcx> {
100 let trait_def_id = self.assoc_id.parent();
101 let args = self
102 .args
103 .to_rustc(tcx)
104 .truncate_to(tcx, tcx.generics_of(trait_def_id));
105 rustc_middle::ty::TraitRef::new(tcx, trait_def_id, args)
106 }
107}
108
109#[derive(Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
110pub struct Expr {
111 kind: Interned<ExprKind>,
112 espan: Option<ESpan>,
113}
114
115impl Expr {
116 pub fn at_opt(self, espan: Option<ESpan>) -> Expr {
117 Expr { kind: self.kind, espan }
118 }
119
120 pub fn at(self, espan: ESpan) -> Expr {
121 self.at_opt(Some(espan))
122 }
123
124 pub fn at_base(self, base: ESpan) -> Expr {
125 if let Some(espan) = self.espan { self.at(espan.with_base(base)) } else { self }
126 }
127
128 pub fn span(&self) -> Option<ESpan> {
129 self.espan
130 }
131
132 pub fn tt() -> Expr {
133 static TRUE: OnceLock<Expr> = OnceLock::new();
134 TRUE.get_or_init(|| ExprKind::Constant(Constant::Bool(true)).intern())
135 .clone()
136 }
137
138 pub fn ff() -> Expr {
139 static FALSE: OnceLock<Expr> = OnceLock::new();
140 FALSE
141 .get_or_init(|| ExprKind::Constant(Constant::Bool(false)).intern())
142 .clone()
143 }
144
145 pub fn and_from_iter(exprs: impl IntoIterator<Item = Expr>) -> Expr {
146 exprs
147 .into_iter()
148 .reduce(|acc, e| Expr::binary_op(BinOp::And, acc, e))
149 .unwrap_or_else(Expr::tt)
150 }
151
152 pub fn or_from_iter(exprs: impl IntoIterator<Item = Expr>) -> Expr {
153 exprs
154 .into_iter()
155 .reduce(|acc, e| Expr::binary_op(BinOp::Or, acc, e))
156 .unwrap_or_else(Expr::ff)
157 }
158
159 pub fn and(e1: impl Into<Expr>, e2: impl Into<Expr>) -> Expr {
160 Expr::and_from_iter([e1.into(), e2.into()])
161 }
162
163 pub fn or(e1: impl Into<Expr>, e2: impl Into<Expr>) -> Expr {
164 Expr::or_from_iter([e1.into(), e2.into()])
165 }
166
167 pub fn zero() -> Expr {
168 static ZERO: OnceLock<Expr> = OnceLock::new();
169 ZERO.get_or_init(|| ExprKind::Constant(Constant::ZERO).intern())
170 .clone()
171 }
172
173 pub fn int_max(int_ty: IntTy) -> Expr {
174 let bit_width: u64 = int_ty
175 .bit_width()
176 .unwrap_or(flux_config::pointer_width().bits());
177 Expr::constant(Constant::int_max(bit_width.try_into().unwrap()))
178 }
179
180 pub fn int_min(int_ty: IntTy) -> Expr {
181 let bit_width: u64 = int_ty
182 .bit_width()
183 .unwrap_or(flux_config::pointer_width().bits());
184 Expr::constant(Constant::int_min(bit_width.try_into().unwrap()))
185 }
186
187 pub fn uint_max(uint_ty: UintTy) -> Expr {
188 let bit_width: u64 = uint_ty
189 .bit_width()
190 .unwrap_or(flux_config::pointer_width().bits());
191 Expr::constant(Constant::uint_max(bit_width.try_into().unwrap()))
192 }
193
194 pub fn nu() -> Expr {
195 Expr::bvar(INNERMOST, BoundVar::ZERO, BoundReftKind::Anon)
196 }
197
198 pub fn is_nu(&self) -> bool {
199 if let ExprKind::Var(Var::Bound(INNERMOST, var)) = self.kind()
200 && var.var == BoundVar::ZERO
201 {
202 true
203 } else {
204 false
205 }
206 }
207
208 pub fn unit() -> Expr {
209 Expr::tuple(List::empty())
210 }
211
212 pub fn var(var: Var) -> Expr {
213 ExprKind::Var(var).intern()
214 }
215
216 pub fn fvar(name: Name) -> Expr {
217 Var::Free(name).to_expr()
218 }
219
220 pub fn evar(evid: EVid) -> Expr {
221 Var::EVar(evid).to_expr()
222 }
223
224 pub fn bvar(debruijn: DebruijnIndex, var: BoundVar, kind: BoundReftKind) -> Expr {
225 Var::Bound(debruijn, BoundReft { var, kind }).to_expr()
226 }
227
228 pub fn early_param(index: u32, name: Symbol) -> Expr {
229 Var::EarlyParam(EarlyReftParam { index, name }).to_expr()
230 }
231
232 pub fn local(local: Local) -> Expr {
233 ExprKind::Local(local).intern()
234 }
235
236 pub fn constant(c: Constant) -> Expr {
237 ExprKind::Constant(c).intern()
238 }
239
240 pub fn const_def_id(c: DefId) -> Expr {
241 ExprKind::ConstDefId(c).intern()
242 }
243
244 pub fn const_generic(param: ParamConst) -> Expr {
245 ExprKind::Var(Var::ConstGeneric(param)).intern()
246 }
247
248 pub fn tuple(flds: List<Expr>) -> Expr {
249 ExprKind::Tuple(flds).intern()
250 }
251
252 pub fn ctor_struct(def_id: DefId, flds: List<Expr>) -> Expr {
253 ExprKind::Ctor(Ctor::Struct(def_id), flds).intern()
254 }
255
256 pub fn ctor_raw_ptr(flds: List<Expr>) -> Expr {
257 ExprKind::Ctor(Ctor::RawPtr, flds).intern()
258 }
259
260 pub fn ctor_enum(def_id: DefId, idx: VariantIdx) -> Expr {
261 ExprKind::Ctor(Ctor::Enum(def_id, idx), List::empty()).intern()
262 }
263
264 pub fn ctor(ctor: Ctor, flds: List<Expr>) -> Expr {
265 ExprKind::Ctor(ctor, flds).intern()
266 }
267
268 pub fn is_ctor(def_id: DefId, variant_idx: VariantIdx, idx: impl Into<Expr>) -> Expr {
269 ExprKind::IsCtor(def_id, variant_idx, idx.into()).intern()
270 }
271
272 pub fn from_bits(bty: &BaseTy, bits: u128) -> Expr {
273 match bty {
275 BaseTy::Int(_) => {
276 let bits = bits as i128;
277 ExprKind::Constant(Constant::from(bits)).intern()
278 }
279 BaseTy::Uint(_) => ExprKind::Constant(Constant::from(bits)).intern(),
280 BaseTy::Bool => ExprKind::Constant(Constant::Bool(bits != 0)).intern(),
281 BaseTy::Char => {
282 let c = char::from_u32(bits.try_into().unwrap()).unwrap();
283 ExprKind::Constant(Constant::Char(c)).intern()
284 }
285 _ => bug!(),
286 }
287 }
288
289 pub fn ite(p: impl Into<Expr>, e1: impl Into<Expr>, e2: impl Into<Expr>) -> Expr {
290 ExprKind::IfThenElse(p.into(), e1.into(), e2.into()).intern()
291 }
292
293 fn empty() -> Expr {
294 let func = Self::global_func(SpecFuncKind::Thy(ThyFunc::SetEmpty));
295 Expr::app(func, List::empty(), List::from_arr([Expr::zero()]))
296 }
297
298 fn singleton(elem: Expr) -> Expr {
299 let func = Self::global_func(SpecFuncKind::Thy(ThyFunc::SetSng));
300 Expr::app(func, List::empty(), List::from_arr([elem]))
301 }
302
303 fn union(expr1: Expr, expr2: Expr) -> Expr {
304 let func = Self::global_func(SpecFuncKind::Thy(ThyFunc::SetCup));
305 Expr::app(func, List::empty(), List::from_arr([expr1, expr2]))
306 }
307
308 pub fn set(elems: List<Expr>) -> Expr {
309 let mut expr = Expr::empty();
310 for elem in &elems {
311 expr = Self::union(expr, Self::singleton(elem.clone()));
312 }
313 expr
314 }
315
316 pub fn abs(lam: Lambda) -> Expr {
317 ExprKind::Abs(lam).intern()
318 }
319
320 pub fn let_(init: Expr, body: Binder<Expr>) -> Expr {
321 ExprKind::Let(init, body).intern()
322 }
323
324 pub fn quant(kind: fhir::QuantKind, dom: QuantDom, body: Binder<Expr>) -> Expr {
325 ExprKind::Quant(kind, dom, body).intern()
326 }
327
328 pub fn hole(kind: HoleKind) -> Expr {
329 ExprKind::Hole(kind).intern()
330 }
331
332 pub fn kvar(kvar: KVar) -> Expr {
333 ExprKind::KVar(kvar).intern()
334 }
335
336 pub fn wkvar(wkvar: WKVar) -> Expr {
337 ExprKind::WKVar(wkvar).intern()
338 }
339
340 pub fn alias(alias: AliasReft, args: List<Expr>) -> Expr {
341 ExprKind::Alias(alias, args).intern()
342 }
343
344 pub fn forall(expr: Binder<Expr>) -> Expr {
345 ExprKind::Quant(fhir::QuantKind::Forall, QuantDom::Unbounded, expr).intern()
346 }
347
348 pub fn exists(expr: Binder<Expr>) -> Expr {
349 ExprKind::Quant(fhir::QuantKind::Exists, QuantDom::Unbounded, expr).intern()
350 }
351
352 pub fn binary_op(op: BinOp, e1: impl Into<Expr>, e2: impl Into<Expr>) -> Expr {
353 ExprKind::BinaryOp(op, e1.into(), e2.into()).intern()
354 }
355
356 pub fn prim_val(op: BinOp, e1: impl Into<Expr>, e2: impl Into<Expr>) -> Expr {
357 Expr::app(InternalFuncKind::Val(op), List::empty(), List::from_arr([e1.into(), e2.into()]))
358 }
359
360 pub fn prim_rel(op: BinOp, e1: impl Into<Expr>, e2: impl Into<Expr>) -> Expr {
361 Expr::app(InternalFuncKind::Rel(op), List::empty(), List::from_arr([e1.into(), e2.into()]))
362 }
363
364 pub fn unit_struct(def_id: DefId) -> Expr {
365 Expr::ctor_struct(def_id, List::empty())
366 }
367
368 pub fn cast(from: Sort, to: Sort, idx: Expr) -> Expr {
369 Expr::app(
370 InternalFuncKind::Cast,
371 List::from_arr([SortArg::Sort(from), SortArg::Sort(to)]),
372 List::from_arr([idx]),
373 )
374 }
375
376 pub fn app(func: impl Into<Expr>, sort_args: List<SortArg>, args: List<Expr>) -> Expr {
377 ExprKind::App(func.into(), sort_args, args).intern()
378 }
379
380 pub fn global_func(kind: SpecFuncKind) -> Expr {
381 ExprKind::GlobalFunc(kind).intern()
382 }
383
384 pub fn internal_func(kind: InternalFuncKind) -> Expr {
385 ExprKind::InternalFunc(kind).intern()
386 }
387
388 pub fn eq(e1: impl Into<Expr>, e2: impl Into<Expr>) -> Expr {
389 ExprKind::BinaryOp(BinOp::Eq, e1.into(), e2.into()).intern()
390 }
391
392 pub fn unary_op(op: UnOp, e: impl Into<Expr>) -> Expr {
393 ExprKind::UnaryOp(op, e.into()).intern()
394 }
395
396 pub fn ne(e1: impl Into<Expr>, e2: impl Into<Expr>) -> Expr {
397 ExprKind::BinaryOp(BinOp::Ne, e1.into(), e2.into()).intern()
398 }
399
400 pub fn ge(e1: impl Into<Expr>, e2: impl Into<Expr>) -> Expr {
401 ExprKind::BinaryOp(BinOp::Ge(Sort::Int), e1.into(), e2.into()).intern()
402 }
403
404 pub fn gt(e1: impl Into<Expr>, e2: impl Into<Expr>) -> Expr {
405 ExprKind::BinaryOp(BinOp::Gt(Sort::Int), e1.into(), e2.into()).intern()
406 }
407
408 pub fn lt(e1: impl Into<Expr>, e2: impl Into<Expr>) -> Expr {
409 ExprKind::BinaryOp(BinOp::Lt(Sort::Int), e1.into(), e2.into()).intern()
410 }
411
412 pub fn le(e1: impl Into<Expr>, e2: impl Into<Expr>) -> Expr {
413 ExprKind::BinaryOp(BinOp::Le(Sort::Int), e1.into(), e2.into()).intern()
414 }
415
416 pub fn implies(e1: impl Into<Expr>, e2: impl Into<Expr>) -> Expr {
417 ExprKind::BinaryOp(BinOp::Imp, e1.into(), e2.into()).intern()
418 }
419
420 pub fn field_proj(e: impl Into<Expr>, proj: FieldProj) -> Expr {
421 ExprKind::FieldProj(e.into(), proj).intern()
422 }
423
424 pub fn field_projs(e: impl Into<Expr>, projs: &[FieldProj]) -> Expr {
425 projs.iter().copied().fold(e.into(), Expr::field_proj)
426 }
427
428 pub fn path_proj(base: Expr, field: FieldIdx) -> Expr {
429 ExprKind::PathProj(base, field).intern()
430 }
431
432 pub fn not(&self) -> Expr {
433 ExprKind::UnaryOp(UnOp::Not, self.clone()).intern()
434 }
435
436 pub fn neg(&self) -> Expr {
437 ExprKind::UnaryOp(UnOp::Neg, self.clone()).intern()
438 }
439
440 pub fn kind(&self) -> &ExprKind {
441 &self.kind
442 }
443
444 pub fn is_atom(&self) -> bool {
447 !matches!(self.kind(), ExprKind::Abs(..) | ExprKind::BinaryOp(..) | ExprKind::Quant(..))
448 }
449
450 pub fn is_trivially_true(&self) -> bool {
453 self.is_true()
454 || matches!(self.kind(), ExprKind::BinaryOp(BinOp::Eq | BinOp::Iff | BinOp::Imp, e1, e2) if e1.erase_spans() == e2.erase_spans())
455 }
456
457 pub fn is_trivially_false(&self) -> bool {
459 self.is_false()
460 }
461
462 fn is_true(&self) -> bool {
464 matches!(self.kind(), ExprKind::Constant(Constant::Bool(true)))
465 }
466
467 fn is_false(&self) -> bool {
469 matches!(self.kind(), ExprKind::Constant(Constant::Bool(false)))
470 }
471
472 pub fn from_const(tcx: TyCtxt, c: &Const) -> Expr {
473 match &c.kind {
474 ConstKind::Param(param_const) => Expr::const_generic(*param_const),
475 ConstKind::Value(ty, ValTree::Leaf(scalar)) => {
476 Expr::constant(Constant::from_scalar_int(tcx, *scalar, ty).unwrap())
477 }
478 ConstKind::Value(_ty, ValTree::Branch(_)) => {
479 bug!("todo: ValTree::Branch {c:?}")
480 }
481 ConstKind::Alias(_) => bug!("unexpected `ConstKind::Alias`"),
483
484 ConstKind::Infer(_) => bug!("unexpected `ConstKind::Infer`"),
485 }
486 }
487
488 fn const_op(op: &BinOp, c1: &Constant, c2: &Constant) -> Option<Constant> {
489 match op {
490 BinOp::Iff => c1.iff(c2),
491 BinOp::Imp => c1.imp(c2),
492 BinOp::Or => c1.or(c2),
493 BinOp::And => c1.and(c2),
494 BinOp::Gt(Sort::Int) => c1.gt(c2),
495 BinOp::Ge(Sort::Int) => c1.ge(c2),
496 BinOp::Lt(Sort::Int) => c2.gt(c1),
497 BinOp::Le(Sort::Int) => c2.ge(c1),
498 BinOp::Eq => Some(c1.eq(c2)),
499 BinOp::Ne => Some(c1.ne(c2)),
500 _ => None,
501 }
502 }
503
504 pub fn simplify(&self, assumed_preds: &SnapshotMap<Expr, ()>) -> Expr {
510 struct Simplify<'a> {
511 assumed_preds: &'a SnapshotMap<Expr, ()>,
512 }
513
514 impl TypeFolder for Simplify<'_> {
515 fn fold_expr(&mut self, expr: &Expr) -> Expr {
516 if self.assumed_preds.get(&expr.erase_spans()).is_some() {
517 return Expr::tt();
518 }
519 let span = expr.span();
520 match expr.kind() {
521 ExprKind::BinaryOp(op, e1, e2) => {
522 let e1 = e1.fold_with(self);
523 let e2 = e2.fold_with(self);
524 match (op, e1.kind(), e2.kind()) {
525 (BinOp::And, ExprKind::Constant(Constant::Bool(false)), _) => {
526 Expr::constant(Constant::Bool(false)).at_opt(e1.span())
527 }
528 (BinOp::And, _, ExprKind::Constant(Constant::Bool(false))) => {
529 Expr::constant(Constant::Bool(false)).at_opt(e2.span())
530 }
531 (BinOp::And, ExprKind::Constant(Constant::Bool(true)), _) => e2,
532 (BinOp::And, _, ExprKind::Constant(Constant::Bool(true))) => e1,
533 (op, ExprKind::Constant(c1), ExprKind::Constant(c2)) => {
534 if let Some(c) = Expr::const_op(op, c1, c2) {
535 Expr::constant(c).at_opt(span.or(e2.span()))
536 } else {
537 Expr::binary_op(op.clone(), e1, e2).at_opt(span)
538 }
539 }
540 _ => Expr::binary_op(op.clone(), e1, e2).at_opt(span),
541 }
542 }
543 ExprKind::UnaryOp(UnOp::Not, e) => {
544 let e = e.fold_with(self);
545 match e.kind() {
546 ExprKind::Constant(Constant::Bool(b)) => {
547 Expr::constant(Constant::Bool(!b))
548 }
549 ExprKind::UnaryOp(UnOp::Not, e) => e.clone(),
550 ExprKind::BinaryOp(BinOp::Eq, e1, e2) => {
551 Expr::binary_op(BinOp::Ne, e1, e2).at_opt(span)
552 }
553 _ => Expr::unary_op(UnOp::Not, e).at_opt(span),
554 }
555 }
556 ExprKind::IfThenElse(p, e1, e2) => {
557 let p = p.fold_with(self);
558 if p.is_trivially_true() {
559 e1.fold_with(self).at_opt(span)
560 } else if p.is_trivially_false() {
561 e2.fold_with(self).at_opt(span)
562 } else {
563 Expr::ite(p, e1.fold_with(self), e2.fold_with(self)).at_opt(span)
564 }
565 }
566 _ => expr.super_fold_with(self),
567 }
568 }
569 }
570 self.fold_with(&mut Simplify { assumed_preds })
571 }
572
573 pub fn to_loc(&self) -> Option<Loc> {
574 match self.kind() {
575 ExprKind::Local(local) => Some(Loc::Local(*local)),
576 ExprKind::Var(var) => Some(Loc::Var(*var)),
577 _ => None,
578 }
579 }
580
581 pub fn to_path(&self) -> Option<Path> {
582 let mut expr = self;
583 let mut proj = vec![];
584 while let ExprKind::PathProj(e, field) = expr.kind() {
585 proj.push(*field);
586 expr = e;
587 }
588 proj.reverse();
589 Some(Path::new(expr.to_loc()?, proj))
590 }
591
592 pub fn is_unit(&self) -> bool {
594 matches!(self.kind(), ExprKind::Tuple(flds) if flds.is_empty())
595 || matches!(self.kind(), ExprKind::Ctor(Ctor::Struct(_), flds) if flds.is_empty())
596 }
597
598 pub fn eta_expand_abs(&self, inputs: &BoundVariableKinds, output: Sort) -> Lambda {
599 let args = (0..inputs.len())
600 .map(|idx| Expr::bvar(INNERMOST, BoundVar::from_usize(idx), BoundReftKind::Anon))
601 .collect();
602 let body = Expr::app(self, List::empty(), args);
603 Lambda::bind_with_vars(body, inputs.clone(), output)
604 }
605
606 pub fn proj_and_reduce(&self, proj: FieldProj) -> Expr {
608 match self.kind() {
609 ExprKind::Tuple(flds) | ExprKind::Ctor(Ctor::Struct(_) | Ctor::RawPtr, flds) => {
610 flds[proj.field_idx() as usize].clone()
611 }
612 _ => Expr::field_proj(self.clone(), proj),
613 }
614 }
615
616 pub fn reduce_ptr_addr(&self) -> Expr {
618 self.proj_and_reduce(FieldProj::RawPtr { field: RawPtrField::Addr })
619 }
620
621 pub fn visit_conj<'a>(&'a self, mut f: impl FnMut(&'a Expr)) {
622 fn go<'a>(e: &'a Expr, f: &mut impl FnMut(&'a Expr)) {
623 if let ExprKind::BinaryOp(BinOp::And, e1, e2) = e.kind() {
624 go(e1, f);
625 go(e2, f);
626 } else {
627 f(e);
628 }
629 }
630 go(self, &mut f);
631 }
632
633 pub fn flatten_conjs(&self) -> Vec<&Expr> {
634 let mut vec = vec![];
635 self.visit_conj(|e| vec.push(e));
636 vec
637 }
638
639 pub fn has_evars(&self) -> bool {
640 struct HasEvars;
641
642 impl TypeVisitor for HasEvars {
643 type BreakTy = ();
644 fn visit_expr(&mut self, expr: &Expr) -> ControlFlow<Self::BreakTy> {
645 if let ExprKind::Var(Var::EVar(_)) = expr.kind() {
646 ControlFlow::Break(())
647 } else {
648 expr.super_visit_with(self)
649 }
650 }
651 }
652
653 self.visit_with(&mut HasEvars).is_break()
654 }
655
656 pub fn erase_spans(&self) -> Expr {
657 struct SpanEraser;
658 impl TypeFolder for SpanEraser {
659 fn fold_expr(&mut self, e: &Expr) -> Expr {
660 e.super_fold_with(self).at_opt(None)
661 }
662 }
663 self.fold_with(&mut SpanEraser)
664 }
665
666 pub fn erase_bound_reft_kind(&self) -> Expr {
674 struct BoundReftKindEraser;
675 impl TypeFolder for BoundReftKindEraser {
676 fn fold_expr(&mut self, expr: &Expr) -> Expr {
677 if let ExprKind::Var(Var::Bound(
678 db_index,
679 BoundReft { var, kind: BoundReftKind::Named(_) },
680 )) = expr.kind()
681 {
682 Expr::bvar(*db_index, *var, BoundReftKind::Anon)
683 } else {
684 expr.super_fold_with(self)
685 }
686 }
687 }
688 self.fold_with(&mut BoundReftKindEraser)
689 }
690
691 pub fn erase_metadata(&self) -> Expr {
692 self.erase_spans().erase_bound_reft_kind()
693 }
694
695 pub fn expand_bin_rels(&self) -> Expr {
709 struct BinRelExpander;
710 impl BinRelExpander {
711 fn expand_bin_rel(&mut self, sort: &Sort, rel: &BinOp, e1: &Expr, e2: &Expr) -> Expr {
712 match sort {
713 Sort::Tuple(sorts) => {
714 let arity = sorts.len();
715 self.apply_bin_rel_rec(sorts, rel, e1, e2, |field| {
716 FieldProj::Tuple { arity, field }
717 })
718 }
719 Sort::App(SortCtor::Adt(sort_def), args)
720 if let Some(variant) = sort_def.opt_struct_variant() =>
721 {
722 let def_id = sort_def.did();
723 let sorts = variant.field_sorts(args);
724 self.apply_bin_rel_rec(&sorts, rel, e1, e2, |field| {
725 FieldProj::Adt { def_id, field }
726 })
727 }
728 _ => {
729 Expr::binary_op(
730 rel.clone(),
731 e1.super_fold_with(self),
732 e2.super_fold_with(self),
733 )
734 }
735 }
736 }
737 fn apply_bin_rel_rec(
739 &mut self,
740 sorts: &[Sort],
741 rel: &BinOp,
742 e1: &Expr,
743 e2: &Expr,
744 mk_proj: impl Fn(u32) -> FieldProj,
745 ) -> Expr {
746 Expr::and_from_iter(sorts.iter().enumerate().map(|(idx, s)| {
747 let proj = mk_proj(idx as u32);
748 let e1 = e1.proj_and_reduce(proj);
749 let e2 = e2.proj_and_reduce(proj);
750 self.expand_bin_rel(s, rel, &e1, &e2)
751 }))
752 }
753 }
754 impl TypeFolder for BinRelExpander {
755 fn fold_expr(&mut self, expr: &Expr) -> Expr {
756 if let ExprKind::BinaryOp(
757 rel @ (BinOp::Le(sort) | BinOp::Lt(sort) | BinOp::Ge(sort) | BinOp::Gt(sort)),
758 e1,
759 e2,
760 ) = expr.kind()
761 {
762 self.expand_bin_rel(sort, rel, e1, e2)
763 } else {
764 expr.super_fold_with(self)
765 }
766 }
767 }
768
769 let mut expander = BinRelExpander {};
770 self.fold_with(&mut expander)
771 }
772
773 pub fn eta_reduce_projs(&self) -> Self {
781 struct EtaReducer;
782 impl TypeFolder for EtaReducer {
783 fn fold_expr(&mut self, expr: &Expr) -> Expr {
784 match expr.kind() {
785 ExprKind::Tuple(subexprs) => {
786 let new_subexprs = subexprs
787 .iter()
788 .map(|subexpr| subexpr.fold_with(self))
789 .collect_vec();
790 if let Some(ExprKind::FieldProj(
791 e_inner,
792 FieldProj::Tuple { arity: _, field: 0 },
793 )) = subexprs.first().map(|e| e.kind())
794 && new_subexprs[1..].iter().zip(1..).all(|(other_e, i)| {
795 if let ExprKind::FieldProj(
796 other_e_inner,
797 FieldProj::Tuple { arity: _, field },
798 ) = other_e.kind()
799 {
800 field == &i && &e_inner.erase_metadata() == other_e_inner
801 } else {
802 false
803 }
804 })
805 {
806 e_inner.clone()
807 } else {
808 expr.clone()
809 }
810 }
811 ExprKind::Ctor(_ctor, subexprs) => {
812 let new_subexprs = subexprs
813 .iter()
814 .map(|subexpr| subexpr.fold_with(self))
815 .collect_vec();
816 if let Some(ExprKind::FieldProj(
817 e_inner,
818 FieldProj::Adt { def_id: _, field: 0 },
819 )) = subexprs.first().map(|e| e.kind())
820 && new_subexprs[1..].iter().zip(1..).all(|(other_e, i)| {
821 if let ExprKind::FieldProj(
822 other_e_inner,
823 FieldProj::Adt { def_id: _, field },
824 ) = other_e.kind()
825 {
826 field == &i && &e_inner.erase_metadata() == other_e_inner
827 } else {
828 false
829 }
830 })
831 {
832 e_inner.clone()
833 } else {
834 expr.clone()
835 }
836 }
837 _ => expr.super_fold_with(self),
838 }
839 }
840 }
841 self.fold_with(&mut EtaReducer)
842 }
843}
844
845#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Debug)]
846pub struct ESpan {
847 pub span: Span,
849 pub base: Option<Span>,
851}
852
853impl ESpan {
854 pub fn new(span: Span) -> Self {
855 Self { span, base: None }
856 }
857
858 pub fn with_base(&self, espan: ESpan) -> Self {
859 Self { span: self.span, base: Some(espan.span) }
860 }
861}
862
863#[derive(
864 Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Debug, TypeFoldable, TypeVisitable,
865)]
866pub enum BinOp {
867 Iff,
868 Imp,
869 Or,
870 And,
871 Eq,
872 Ne,
873 Gt(Sort),
874 Ge(Sort),
875 Lt(Sort),
876 Le(Sort),
877 Add(Sort),
878 Sub(Sort),
879 Mul(Sort),
880 Div(Sort),
881 Mod(Sort),
882 BitAnd(Sort),
883 BitOr(Sort),
884 BitXor(Sort),
885 BitShl(Sort),
886 BitShr(Sort),
887}
888
889#[derive(Clone, Copy, PartialEq, Eq, Hash, Encodable, Debug, Decodable)]
890pub enum UnOp {
891 Not,
892 Neg,
893}
894
895#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, TyEncodable, TyDecodable)]
896pub enum Ctor {
897 Struct(DefId),
899 Enum(DefId, VariantIdx),
901 RawPtr,
903}
904
905impl Ctor {
906 fn is_enum(&self) -> bool {
907 matches!(self, Self::Enum(..))
908 }
909
910 pub fn def_id_and_variant(&self) -> Option<(DefId, VariantIdx)> {
911 match self {
912 Self::Struct(def_id) => Some((*def_id, FIRST_VARIANT)),
913 Self::Enum(def_id, variant_idx) => Some((*def_id, *variant_idx)),
914 Self::RawPtr => None,
915 }
916 }
917}
918
919#[derive(Debug, Clone, TyEncodable, TyDecodable, PartialEq, Eq, Hash)]
933pub enum InternalFuncKind {
934 Val(BinOp),
936 Rel(BinOp),
938 Cast,
940}
941
942#[derive(Debug, Clone, TyEncodable, TyDecodable, PartialEq, Eq, Hash)]
943pub enum SpecFuncKind {
944 Thy(liquid_fixpoint::ThyFunc),
946 Def(FluxDefId),
948}
949
950#[derive(
951 Clone, PartialEq, Eq, Hash, TyEncodable, Debug, TyDecodable, TypeVisitable, TypeFoldable,
952)]
953pub enum QuantDom {
954 Bounded { start: usize, end: usize },
955 Unbounded,
956}
957
958#[derive(Clone, PartialEq, Eq, Hash, TyEncodable, Debug, TyDecodable)]
959pub enum ExprKind {
960 Var(Var),
961 Local(Local),
962 Constant(Constant),
963 ConstDefId(DefId),
965 BinaryOp(BinOp, Expr, Expr),
966 GlobalFunc(SpecFuncKind),
967 InternalFunc(InternalFuncKind),
968 UnaryOp(UnOp, Expr),
969 FieldProj(Expr, FieldProj),
970 Ctor(Ctor, List<Expr>),
972 Tuple(List<Expr>),
973 PathProj(Expr, FieldIdx),
974 IfThenElse(Expr, Expr, Expr),
975 KVar(KVar),
976 WKVar(WKVar),
977 Alias(AliasReft, List<Expr>),
978 Let(Expr, Binder<Expr>),
979 App(Expr, List<SortArg>, List<Expr>),
985 Abs(Lambda),
995
996 Quant(fhir::QuantKind, QuantDom, Binder<Expr>),
998 Hole(HoleKind),
1012 IsCtor(DefId, VariantIdx, Expr),
1014}
1015
1016impl ExprKind {
1017 fn intern(self) -> Expr {
1018 Expr { kind: Interned::new(self), espan: None }
1019 }
1020}
1021
1022#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Debug)]
1023pub enum AggregateKind {
1024 Tuple(usize),
1025 Adt(DefId),
1026}
1027
1028#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Debug)]
1029pub enum FieldProj {
1030 Tuple { arity: usize, field: u32 },
1031 Adt { def_id: DefId, field: u32 },
1032 RawPtr { field: RawPtrField },
1033}
1034
1035#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Debug)]
1036pub enum RawPtrField {
1037 Base,
1038 Addr,
1039 Size,
1040}
1041
1042struct RawPtrFieldData {
1043 field: RawPtrField,
1044 index: u32,
1045 name: &'static str,
1046 sort: Sort,
1047}
1048
1049impl FieldProj {
1050 pub fn arity(&self, genv: GlobalEnv) -> QueryResult<usize> {
1051 match self {
1052 FieldProj::Tuple { arity, .. } => Ok(*arity),
1053 FieldProj::Adt { def_id, .. } => {
1054 Ok(genv.adt_sort_def_of(*def_id)?.struct_variant().fields())
1055 }
1056 FieldProj::RawPtr { .. } => Ok(RawPtrField::arity()),
1057 }
1058 }
1059
1060 pub fn field_idx(&self) -> u32 {
1061 match self {
1062 FieldProj::Tuple { field, .. } | FieldProj::Adt { field, .. } => *field,
1063 FieldProj::RawPtr { field } => field.index(),
1064 }
1065 }
1066}
1067
1068impl RawPtrField {
1069 const DATA: [RawPtrFieldData; 3] = [
1070 RawPtrFieldData { field: Self::Base, index: 0, name: "base", sort: Sort::Int },
1071 RawPtrFieldData { field: Self::Addr, index: 1, name: "addr", sort: Sort::Int },
1072 RawPtrFieldData { field: Self::Size, index: 2, name: "size", sort: Sort::Int },
1073 ];
1074
1075 pub fn iter() -> impl ExactSizeIterator<Item = Self> {
1076 Self::DATA.iter().map(|data| data.field)
1077 }
1078
1079 pub fn arity() -> usize {
1080 Self::DATA.len()
1081 }
1082
1083 fn data(self) -> &'static RawPtrFieldData {
1084 Self::DATA.iter().find(|data| data.field == self).unwrap()
1085 }
1086
1087 pub fn from_name(name: Symbol) -> Option<Self> {
1088 Self::DATA
1089 .iter()
1090 .find(|data| data.name == name.as_str())
1091 .map(|data| data.field)
1092 }
1093
1094 pub fn from_index(index: u32) -> Option<Self> {
1095 Self::DATA
1096 .iter()
1097 .find(|data| data.index == index)
1098 .map(|data| data.field)
1099 }
1100
1101 pub fn sort(self) -> Sort {
1102 self.data().sort.clone()
1103 }
1104
1105 pub fn index(self) -> u32 {
1106 self.data().index
1107 }
1108
1109 pub fn name(self) -> &'static str {
1110 self.data().name
1111 }
1112
1113 pub fn symbol(self) -> Symbol {
1114 match self {
1115 Self::Base => sym::base,
1116 Self::Addr => sym::addr,
1117 Self::Size => rustc_span::sym::size,
1118 }
1119 }
1120}
1121
1122#[derive(
1128 Debug, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, TypeFoldable, TypeVisitable,
1129)]
1130pub enum HoleKind {
1131 Pred,
1136 Expr(Sort),
1143}
1144
1145#[derive(Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, TypeVisitable, TypeFoldable)]
1150pub struct KVar {
1151 pub kvid: KVid,
1152 pub self_args: usize,
1154 pub args: List<Expr>,
1157}
1158
1159#[derive(
1160 Debug, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, TypeVisitable, TypeFoldable,
1161)]
1162pub struct WKVid {
1163 pub parent_fn: DefId,
1166 pub id: KVid,
1169}
1170
1171impl WKVid {
1172 pub fn new(parent_fn: DefId, id: KVid) -> Self {
1173 Self { parent_fn, id }
1174 }
1175}
1176
1177#[derive(Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, TypeVisitable, TypeFoldable)]
1182pub struct WKVar {
1183 pub wkvid: WKVid,
1184 pub self_args: usize,
1218 pub args: List<Expr>,
1220}
1221
1222#[derive(Clone, Debug, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Encodable, Decodable)]
1223pub struct EarlyReftParam {
1224 pub index: u32,
1225 pub name: Symbol,
1226}
1227
1228#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Encodable, Decodable, Debug)]
1229pub struct BoundReft {
1230 pub var: BoundVar,
1231 pub kind: BoundReftKind,
1232}
1233
1234#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, TyEncodable, TyDecodable)]
1235pub enum Var {
1236 Free(Name),
1237 Bound(DebruijnIndex, BoundReft),
1238 EarlyParam(EarlyReftParam),
1239 EVar(EVid),
1240 ConstGeneric(ParamConst),
1241}
1242
1243#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord, TyEncodable, TyDecodable)]
1244pub struct Path {
1245 pub loc: Loc,
1246 projection: List<FieldIdx>,
1247}
1248
1249#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, TyEncodable, TyDecodable)]
1250pub enum Loc {
1251 Local(Local),
1252 Var(Var),
1253}
1254
1255newtype_index! {
1256 #[debug_format = "?{}e"]
1258 #[orderable]
1259 #[encodable]
1260 pub struct EVid {}
1261}
1262
1263newtype_index! {
1264 #[debug_format = "$k{}"]
1265 #[encodable]
1266 pub struct KVid {}
1267}
1268
1269newtype_index! {
1270 #[debug_format = "a{}"]
1271 #[orderable]
1272 #[encodable]
1273 pub struct Name {}
1274}
1275
1276#[derive(Copy, Debug, Clone)]
1277pub enum NameProvenance {
1278 Unknown,
1279 UnfoldBoundReft(BoundReftKind),
1280}
1281
1282impl NameProvenance {
1283 pub fn opt_symbol(&self) -> Option<Symbol> {
1284 match &self {
1285 NameProvenance::UnfoldBoundReft(BoundReftKind::Named(name)) => Some(*name),
1286 _ => None,
1287 }
1288 }
1289}
1290
1291#[derive(PartialEq, Eq, Hash, Debug)]
1292pub enum PrettyVar<V> {
1293 Local(V),
1294 Param(EarlyReftParam),
1295}
1296
1297impl<V: Copy + Into<usize>> PrettyVar<V> {
1298 pub fn as_subscript(&self) -> String {
1299 let idx = match self {
1300 PrettyVar::Local(v) => (*v).into(),
1301 PrettyVar::Param(p) => p.index as usize,
1302 };
1303 as_subscript(idx)
1304 }
1305}
1306
1307pub struct PrettyMap<V: Eq + Hash> {
1308 map: UnordMap<PrettyVar<V>, String>,
1309 count: UnordMap<Symbol, usize>,
1310}
1311
1312impl<V: Eq + Hash + Copy + Into<usize>> PrettyMap<V> {
1313 pub fn new() -> Self {
1314 PrettyMap { map: UnordMap::default(), count: UnordMap::default() }
1315 }
1316
1317 pub fn set(&mut self, var: PrettyVar<V>, prefix: Option<Symbol>) -> String {
1318 if let Some(symbol) = self.map.get(&var) {
1320 return symbol.clone();
1321 }
1322 let symbol = if let Some(prefix) = prefix {
1324 let index = self.count.entry(prefix).or_insert(0);
1325 let symbol = format!("{}{}", prefix, as_subscript(*index));
1326 *index += 1;
1327 symbol
1328 } else {
1329 format!("a'{}", var.as_subscript())
1330 };
1331 self.map.insert(var, symbol.clone());
1332 symbol
1333 }
1334
1335 pub fn get(&self, key: &PrettyVar<V>) -> String {
1336 match self.map.get(key) {
1337 Some(s) => s.clone(),
1338 None => format!("a'{}", key.as_subscript()),
1339 }
1340 }
1341}
1342
1343impl KVar {
1344 pub fn new(kvid: KVid, self_args: usize, args: Vec<Expr>) -> Self {
1345 KVar { kvid, self_args, args: List::from_vec(args) }
1346 }
1347
1348 fn self_args(&self) -> &[Expr] {
1349 &self.args[..self.self_args]
1350 }
1351
1352 fn scope(&self) -> &[Expr] {
1353 &self.args[self.self_args..]
1354 }
1355}
1356
1357impl WKVar {
1358 fn self_args(&self) -> &[Expr] {
1359 &self.args[..self.self_args]
1360 }
1361
1362 fn scope(&self) -> &[Expr] {
1363 &self.args[self.self_args..]
1364 }
1365}
1366
1367impl Var {
1368 pub fn to_expr(&self) -> Expr {
1369 Expr::var(*self)
1370 }
1371
1372 pub fn shift_in(&self, amount: u32) -> Self {
1373 match self {
1374 Var::Bound(idx, breft) => Var::Bound(idx.shifted_in(amount), *breft),
1375 _ => *self,
1376 }
1377 }
1378
1379 pub fn shift_out(&self, amount: u32) -> Self {
1380 match self {
1381 Var::Bound(idx, breft) => Var::Bound(idx.shifted_out(amount), *breft),
1382 _ => *self,
1383 }
1384 }
1385}
1386
1387impl Path {
1388 pub fn new(loc: Loc, projection: impl Into<List<FieldIdx>>) -> Path {
1389 Path { loc, projection: projection.into() }
1390 }
1391
1392 pub fn projection(&self) -> &[FieldIdx] {
1393 &self.projection[..]
1394 }
1395
1396 pub fn to_expr(&self) -> Expr {
1397 self.projection
1398 .iter()
1399 .fold(self.loc.to_expr(), |e, f| Expr::path_proj(e, *f))
1400 }
1401
1402 pub fn to_loc(&self) -> Option<Loc> {
1403 if self.projection.is_empty() { Some(self.loc) } else { None }
1404 }
1405}
1406
1407impl Loc {
1408 pub fn to_expr(&self) -> Expr {
1409 match self {
1410 Loc::Local(local) => Expr::local(*local),
1411 Loc::Var(var) => Expr::var(*var),
1412 }
1413 }
1414}
1415
1416macro_rules! impl_ops {
1417 ($($op:ident: $method:ident),*) => {$(
1418 impl<Rhs> std::ops::$op<Rhs> for Expr
1419 where
1420 Rhs: Into<Expr>,
1421 {
1422 type Output = Expr;
1423
1424 fn $method(self, rhs: Rhs) -> Self::Output {
1425 let sort = crate::rty::Sort::Int;
1426 Expr::binary_op(BinOp::$op(sort), self, rhs)
1427 }
1428 }
1429
1430 impl<Rhs> std::ops::$op<Rhs> for &Expr
1431 where
1432 Rhs: Into<Expr>,
1433 {
1434 type Output = Expr;
1435
1436 fn $method(self, rhs: Rhs) -> Self::Output {
1437 let sort = crate::rty::Sort::Int;
1438 Expr::binary_op(BinOp::$op(sort), self, rhs)
1439 }
1440 }
1441 )*};
1442}
1443impl_ops!(Add: add, Sub: sub, Mul: mul, Div: div);
1444
1445impl From<i32> for Expr {
1446 fn from(value: i32) -> Self {
1447 Expr::constant(Constant::from(value))
1448 }
1449}
1450
1451impl From<&Expr> for Expr {
1452 fn from(e: &Expr) -> Self {
1453 e.clone()
1454 }
1455}
1456
1457impl From<Path> for Expr {
1458 fn from(path: Path) -> Self {
1459 path.to_expr()
1460 }
1461}
1462
1463impl From<Name> for Expr {
1464 fn from(name: Name) -> Self {
1465 Expr::fvar(name)
1466 }
1467}
1468
1469impl From<Var> for Expr {
1470 fn from(var: Var) -> Self {
1471 Expr::var(var)
1472 }
1473}
1474
1475impl From<SpecFuncKind> for Expr {
1476 fn from(kind: SpecFuncKind) -> Self {
1477 Expr::global_func(kind)
1478 }
1479}
1480
1481impl From<InternalFuncKind> for Expr {
1482 fn from(kind: InternalFuncKind) -> Self {
1483 Expr::internal_func(kind)
1484 }
1485}
1486
1487impl From<Loc> for Path {
1488 fn from(loc: Loc) -> Self {
1489 Path::new(loc, vec![])
1490 }
1491}
1492
1493impl From<Name> for Loc {
1494 fn from(name: Name) -> Self {
1495 Loc::Var(Var::Free(name))
1496 }
1497}
1498
1499impl From<Local> for Loc {
1500 fn from(local: Local) -> Self {
1501 Loc::Local(local)
1502 }
1503}
1504
1505#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Encodable, Decodable)]
1506pub struct Real(pub Symbol);
1507
1508#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Encodable, Decodable)]
1509pub enum Constant {
1510 Int(BigInt),
1511 Real(Real),
1512 Bool(bool),
1513 Str(Symbol),
1514 Char(char),
1515 BitVec(u128, u32),
1516}
1517
1518impl Constant {
1519 pub const ZERO: Constant = Constant::Int(BigInt::ZERO);
1520 pub const ONE: Constant = Constant::Int(BigInt::ONE);
1521 pub const TRUE: Constant = Constant::Bool(true);
1522
1523 fn to_bool(self) -> Option<bool> {
1524 match self {
1525 Constant::Bool(b) => Some(b),
1526 _ => None,
1527 }
1528 }
1529
1530 fn to_int(self) -> Option<BigInt> {
1531 match self {
1532 Constant::Int(n) => Some(n),
1533 _ => None,
1534 }
1535 }
1536
1537 pub fn iff(&self, other: &Constant) -> Option<Constant> {
1538 let b1 = self.to_bool()?;
1539 let b2 = other.to_bool()?;
1540 Some(Constant::Bool(b1 == b2))
1541 }
1542
1543 pub fn imp(&self, other: &Constant) -> Option<Constant> {
1544 let b1 = self.to_bool()?;
1545 let b2 = other.to_bool()?;
1546 Some(Constant::Bool(!b1 || b2))
1547 }
1548
1549 pub fn or(&self, other: &Constant) -> Option<Constant> {
1550 let b1 = self.to_bool()?;
1551 let b2 = other.to_bool()?;
1552 Some(Constant::Bool(b1 || b2))
1553 }
1554
1555 pub fn and(&self, other: &Constant) -> Option<Constant> {
1556 let b1 = self.to_bool()?;
1557 let b2 = other.to_bool()?;
1558 Some(Constant::Bool(b1 && b2))
1559 }
1560
1561 pub fn eq(&self, other: &Constant) -> Constant {
1562 Constant::Bool(*self == *other)
1563 }
1564
1565 pub fn ne(&self, other: &Constant) -> Constant {
1566 Constant::Bool(*self != *other)
1567 }
1568
1569 pub fn gt(&self, other: &Constant) -> Option<Constant> {
1570 let n1 = self.to_int()?;
1571 let n2 = other.to_int()?;
1572 Some(Constant::Bool(n1 > n2))
1573 }
1574
1575 pub fn ge(&self, other: &Constant) -> Option<Constant> {
1576 let n1 = self.to_int()?;
1577 let n2 = other.to_int()?;
1578 Some(Constant::Bool(n1 >= n2))
1579 }
1580
1581 pub fn from_scalar_int<'tcx, T>(tcx: TyCtxt<'tcx>, scalar: ScalarInt, t: &T) -> Option<Self>
1582 where
1583 T: ToRustc<'tcx, T = rustc_middle::ty::Ty<'tcx>>,
1584 {
1585 use rustc_middle::ty::TyKind;
1586 let ty = t.to_rustc(tcx);
1587 match ty.kind() {
1588 TyKind::Int(int_ty) => Some(Constant::from(scalar_to_int(tcx, scalar, *int_ty))),
1589 TyKind::Uint(uint_ty) => Some(Constant::from(scalar_to_uint(tcx, scalar, *uint_ty))),
1590 TyKind::Bool => {
1591 let b = scalar_to_bits(tcx, scalar, ty);
1592 Some(Constant::Bool(b != 0))
1593 }
1594 TyKind::Char => {
1595 let b = scalar_to_bits(tcx, scalar, ty);
1596 Some(Constant::Char(char::from_u32(b as u32)?))
1597 }
1598 _ => bug!(),
1599 }
1600 }
1601
1602 pub fn int_min(bit_width: u32) -> Constant {
1604 Constant::Int(BigInt::int_min(bit_width))
1605 }
1606
1607 pub fn int_max(bit_width: u32) -> Constant {
1609 Constant::Int(BigInt::int_max(bit_width))
1610 }
1611
1612 pub fn uint_max(bit_width: u32) -> Constant {
1614 Constant::Int(BigInt::uint_max(bit_width))
1615 }
1616}
1617
1618impl From<i32> for Constant {
1619 fn from(c: i32) -> Self {
1620 Constant::Int(c.into())
1621 }
1622}
1623
1624impl From<usize> for Constant {
1625 fn from(u: usize) -> Self {
1626 Constant::Int(u.into())
1627 }
1628}
1629
1630impl From<u32> for Constant {
1631 fn from(c: u32) -> Self {
1632 Constant::Int(c.into())
1633 }
1634}
1635
1636impl From<u64> for Constant {
1637 fn from(c: u64) -> Self {
1638 Constant::Int(c.into())
1639 }
1640}
1641
1642impl From<u128> for Constant {
1643 fn from(c: u128) -> Self {
1644 Constant::Int(c.into())
1645 }
1646}
1647
1648impl From<i128> for Constant {
1649 fn from(c: i128) -> Self {
1650 Constant::Int(c.into())
1651 }
1652}
1653
1654impl From<bool> for Constant {
1655 fn from(b: bool) -> Self {
1656 Constant::Bool(b)
1657 }
1658}
1659
1660impl From<Symbol> for Constant {
1661 fn from(s: Symbol) -> Self {
1662 Constant::Str(s)
1663 }
1664}
1665
1666impl From<char> for Constant {
1667 fn from(c: char) -> Self {
1668 Constant::Char(c)
1669 }
1670}
1671
1672impl_internable!(ExprKind);
1673impl_slice_internable!(Expr, KVar);
1674
1675#[derive(Debug)]
1676pub struct FieldBind<T> {
1677 pub name: Symbol,
1678 pub value: T,
1679}
1680
1681impl<T: Pretty> Pretty for FieldBind<T> {
1682 fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1683 w!(cx, f, "{}: {:?}", ^self.name, &self.value)
1684 }
1685}
1686
1687pub(crate) mod pretty {
1688
1689 use flux_rustc_bridge::def_id_to_string;
1690
1691 use super::*;
1692 use crate::name_of_thy_func;
1693
1694 #[derive(PartialEq, Eq, PartialOrd, Ord)]
1695 enum Precedence {
1696 Iff,
1697 Imp,
1698 Or,
1699 And,
1700 Cmp,
1701 Bitvec,
1702 AddSub,
1703 MulDiv,
1704 }
1705
1706 impl BinOp {
1707 fn precedence(&self) -> Precedence {
1708 match self {
1709 BinOp::Iff => Precedence::Iff,
1710 BinOp::Imp => Precedence::Imp,
1711 BinOp::Or => Precedence::Or,
1712 BinOp::And => Precedence::And,
1713 BinOp::Eq
1714 | BinOp::Ne
1715 | BinOp::Gt(_)
1716 | BinOp::Lt(_)
1717 | BinOp::Ge(_)
1718 | BinOp::Le(_) => Precedence::Cmp,
1719 BinOp::Add(_) | BinOp::Sub(_) => Precedence::AddSub,
1720 BinOp::Mul(_) | BinOp::Div(_) | BinOp::Mod(_) => Precedence::MulDiv,
1721 BinOp::BitAnd(_)
1722 | BinOp::BitOr(_)
1723 | BinOp::BitShl(_)
1724 | BinOp::BitShr(_)
1725 | BinOp::BitXor(_) => Precedence::Bitvec,
1726 }
1727 }
1728 }
1729
1730 impl Precedence {
1731 pub fn is_associative(&self) -> bool {
1732 !matches!(self, Precedence::Imp | Precedence::Cmp)
1733 }
1734 }
1735
1736 pub fn should_parenthesize(op: &BinOp, child: &Expr) -> bool {
1737 if let ExprKind::BinaryOp(child_op, ..) = child.kind() {
1738 child_op.precedence() < op.precedence()
1739 || (child_op.precedence() == op.precedence() && !op.precedence().is_associative())
1740 } else {
1741 false
1742 }
1743 }
1744
1745 impl Pretty for Ctor {
1746 fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1747 match self {
1748 Ctor::Struct(def_id) => {
1749 w!(cx, f, "{:?}", def_id)
1750 }
1751 Ctor::Enum(def_id, variant_idx) => {
1752 w!(cx, f, "{:?}::{:?}", def_id, ^variant_idx)
1753 }
1754 Ctor::RawPtr => w!(cx, f, "ptr"),
1755 }
1756 }
1757 }
1758
1759 impl Pretty for fhir::QuantKind {
1760 fn fmt(&self, _cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1761 match self {
1762 fhir::QuantKind::Exists => w!(cx, f, "∃"),
1763 fhir::QuantKind::Forall => w!(cx, f, "∀"),
1764 }
1765 }
1766 }
1767
1768 impl Pretty for InternalFuncKind {
1769 fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1770 match self {
1771 InternalFuncKind::Val(op) => w!(cx, f, "[{:?}]", op),
1772 InternalFuncKind::Rel(op) => w!(cx, f, "[{:?}]?", op),
1773 InternalFuncKind::Cast => w!(cx, f, "cast"),
1774 }
1775 }
1776 }
1777
1778 impl Pretty for QuantDom {
1779 fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1780 match self {
1781 QuantDom::Bounded { start, end } => w!(cx, f, "in {} .. {}", ^start, ^end),
1782 QuantDom::Unbounded => Ok(()),
1783 }
1784 }
1785 }
1786
1787 impl Pretty for Expr {
1788 fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1789 let e = if cx.simplify_exprs {
1790 self.simplify(&SnapshotMap::default())
1791 } else {
1792 self.clone()
1793 };
1794 match e.kind() {
1795 ExprKind::Var(var) => w!(cx, f, "{:?}", var),
1796 ExprKind::Local(local) => w!(cx, f, "{:?}", ^local),
1797 ExprKind::ConstDefId(did) => w!(cx, f, "{}", ^def_id_to_string(*did)),
1798 ExprKind::Constant(c) => w!(cx, f, "{:?}", c),
1799
1800 ExprKind::BinaryOp(op, e1, e2) => {
1801 if should_parenthesize(op, e1) {
1802 w!(cx, f, "({:?})", e1)?;
1803 } else {
1804 w!(cx, f, "{:?}", e1)?;
1805 }
1806 if matches!(op, BinOp::Div(_)) {
1807 w!(cx, f, "{:?}", op)?;
1808 } else {
1809 w!(cx, f, " {:?} ", op)?;
1810 }
1811 if should_parenthesize(op, e2) {
1812 w!(cx, f, "({:?})", e2)?;
1813 } else {
1814 w!(cx, f, "{:?}", e2)?;
1815 }
1816 Ok(())
1817 }
1818 ExprKind::UnaryOp(op, e) => {
1819 if e.is_atom() {
1820 w!(cx, f, "{:?}{:?}", op, e)
1821 } else {
1822 w!(cx, f, "{:?}({:?})", op, e)
1823 }
1824 }
1825 ExprKind::FieldProj(e, proj) if let ExprKind::Ctor(_, _) = e.kind() => {
1826 w!(cx, f, "{:?}", e.proj_and_reduce(*proj))
1829 }
1830 ExprKind::FieldProj(e, proj) => {
1831 if e.is_atom() {
1832 w!(cx, f, "{:?}.{}", e, ^fmt_field_proj(cx, *proj))
1833 } else {
1834 w!(cx, f, "({:?}).{}", e, ^fmt_field_proj(cx, *proj))
1835 }
1836 }
1837 ExprKind::Tuple(flds) => {
1838 if let [e] = &flds[..] {
1839 w!(cx, f, "({:?},)", e)
1840 } else {
1841 w!(cx, f, "({:?})", join!(", ", flds))
1842 }
1843 }
1844 ExprKind::IsCtor(def_id, variant_idx, idx) => {
1845 w!(cx, f, "({:?} is {:?}::{:?})", idx, def_id, ^variant_idx)
1846 }
1847 ExprKind::Ctor(ctor, flds) => {
1848 if matches!(ctor, Ctor::RawPtr) {
1849 let fields = iter::zip(RawPtrField::iter(), flds)
1850 .map(|(field, value)| {
1851 FieldBind { name: field.symbol(), value: value.clone() }
1852 })
1853 .collect_vec();
1854 return w!(cx, f, "ptr {{ {:?} }}", join!(", ", fields));
1855 }
1856 let Some((def_id, variant_idx)) = ctor.def_id_and_variant() else {
1857 unreachable!()
1858 };
1859 if let Some(adt_sort_def) = cx.adt_sort_def_of(def_id) {
1860 let variant = adt_sort_def.variant(variant_idx).field_names();
1861 let fields = iter::zip(variant, flds)
1862 .map(|(name, value)| FieldBind { name: *name, value: value.clone() })
1863 .collect_vec();
1864 match ctor {
1865 Ctor::Struct(_) => {
1866 w!(cx, f, "{:?} {{ {:?} }}", def_id, join!(", ", fields))
1867 }
1868 Ctor::Enum(_, idx) => {
1869 if fields.is_empty() {
1870 w!(cx, f, "{:?}::{:?}", def_id, ^idx.index())
1871 } else {
1872 w!(cx, f, "{:?}::{:?}({:?})", def_id, ^idx.index(), join!(", ", fields))
1873 }
1874 }
1875 Ctor::RawPtr => unreachable!(),
1876 }
1877 } else {
1878 match ctor {
1879 Ctor::Struct(_) => {
1880 w!(cx, f, "{:?} {{ {:?} }}", def_id, join!(", ", flds))
1881 }
1882 Ctor::Enum(_, idx) => {
1883 w!(cx, f, "{:?}::{:?} {{ {:?} }}", def_id, ^idx, join!(", ", flds))
1884 }
1885 Ctor::RawPtr => unreachable!(),
1886 }
1887 }
1888 }
1889 ExprKind::PathProj(e, field) => {
1890 if e.is_atom() {
1891 w!(cx, f, "{:?}.{:?}", e, field)
1892 } else {
1893 w!(cx, f, "({:?}).{:?}", e, field)
1894 }
1895 }
1896 ExprKind::App(func, _, args) => {
1897 w!(cx, f, "{:?}({})",
1898 parens!(func, !func.is_atom()),
1899 ^args
1900 .iter()
1901 .format_with(", ", |arg, f| f(&format_args_cx!(cx, "{:?}", arg)))
1902 )
1903 }
1904 ExprKind::IfThenElse(p, e1, e2) => {
1905 w!(cx, f, "if {:?} {{ {:?} }} else {{ {:?} }}", p, e1, e2)
1906 }
1907 ExprKind::Hole(_) => {
1908 w!(cx, f, "*")
1909 }
1910 ExprKind::KVar(kvar) => {
1911 w!(cx, f, "{:?}", kvar)
1912 }
1913 ExprKind::WKVar(wkvar) => {
1914 w!(cx, f, "{:?}", wkvar)
1915 }
1916 ExprKind::Alias(alias, args) => {
1917 w!(cx, f, "{:?}({:?})", alias, join!(", ", args))
1918 }
1919 ExprKind::Abs(lam) => {
1920 w!(cx, f, "{:?}", lam)
1921 }
1922 ExprKind::GlobalFunc(SpecFuncKind::Def(did)) => {
1923 w!(cx, f, "{}", ^did.name())
1924 }
1925 ExprKind::GlobalFunc(SpecFuncKind::Thy(itf)) => {
1926 if let Some(name) = name_of_thy_func(*itf) {
1927 w!(cx, f, "{}", ^name)
1928 } else {
1929 w!(cx, f, "<error>")
1930 }
1931 }
1932 ExprKind::InternalFunc(func) => {
1933 w!(cx, f, "{:?}", func)
1934 }
1935 ExprKind::Quant(kind, dom, body) => {
1936 let vars = body.vars();
1937 cx.with_bound_vars(vars, || {
1938 w!(cx, f, "{:?} {:?} {{ {:?} }}", kind, dom, body.skip_binder_ref())
1939 })
1940 }
1941 ExprKind::Let(init, body) => {
1942 let vars = body.vars();
1943 cx.with_bound_vars(vars, || {
1944 cx.fmt_bound_vars(false, "(let ", vars, " = ", f)?;
1945 w!(cx, f, "{:?} in {:?})", init, body.skip_binder_ref())
1946 })
1947 }
1948 }
1949 }
1950 }
1951
1952 fn fmt_field_proj(cx: &PrettyCx, proj: FieldProj) -> String {
1953 if let FieldProj::Adt { def_id, field } = proj
1954 && let Some(adt_sort_def) = cx.adt_sort_def_of(def_id)
1955 {
1956 format!("{}", adt_sort_def.struct_variant().field_names()[field as usize])
1957 } else if let FieldProj::RawPtr { field } = proj {
1958 field.name().to_string()
1959 } else {
1960 format!("{}", proj.field_idx())
1961 }
1962 }
1963
1964 impl Pretty for Constant {
1965 fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1966 match self {
1967 Constant::Int(i) => w!(cx, f, "{i}"),
1968 Constant::BitVec(i, sz) => w!(cx, f, "bv({i}, {sz})"),
1969 Constant::Real(r) => w!(cx, f, "{}", ^r.0),
1970 Constant::Bool(b) => w!(cx, f, "{b}"),
1971 Constant::Str(sym) => w!(cx, f, "\"{sym}\""),
1972 Constant::Char(c) => w!(cx, f, "\'{c}\'"),
1973 }
1974 }
1975 }
1976
1977 impl Pretty for AliasReft {
1978 fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1979 w!(cx, f, "<({:?}) as {:?}", &self.args[0], self.assoc_id.parent())?;
1980 let args = &self.args[1..];
1981 if !args.is_empty() {
1982 w!(cx, f, "<{:?}>", join!(", ", args))?;
1983 }
1984 w!(cx, f, ">::{}", ^self.assoc_id.name())
1985 }
1986 }
1987
1988 impl Pretty for Lambda {
1989 fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1990 let vars = self.body.vars();
1991 cx.with_bound_vars(vars, || {
1994 cx.fmt_bound_vars(false, "λ", vars, ". ", f)?;
1995 w!(cx, f, "{:?}", self.body.as_ref().skip_binder())
1996 })
1997 }
1998 }
1999
2000 impl Pretty for Var {
2001 fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2002 match self {
2003 Var::Bound(debruijn, var) => cx.fmt_bound_reft(*debruijn, *var, f),
2004 Var::EarlyParam(var) => w!(cx, f, "{}", ^var.name),
2005 Var::Free(name) => w!(cx, f, "{:?}", ^name),
2006 Var::EVar(evar) => w!(cx, f, "{:?}", ^evar),
2007 Var::ConstGeneric(param) => w!(cx, f, "{}", ^param.name),
2008 }
2009 }
2010 }
2011
2012 impl Pretty for KVar {
2013 fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2014 w!(cx, f, "{:?}", ^self.kvid)?;
2015 match cx.kvar_args {
2016 KVarArgs::All => {
2017 w!(
2018 cx,
2019 f,
2020 "({:?})[{:?}]",
2021 join!(", ", self.self_args()),
2022 join!(", ", self.scope())
2023 )?;
2024 }
2025 KVarArgs::SelfOnly => w!(cx, f, "({:?})", join!(", ", self.self_args()))?,
2026 KVarArgs::Hide => {}
2027 }
2028 Ok(())
2029 }
2030 }
2031
2032 impl Pretty for WKVar {
2033 fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2034 w!(cx, f, "$wk{}_{}", ^self.wkvid.id.index(), ^cx.tcx().def_path_str(self.wkvid.parent_fn))?;
2037 w!(cx, f, "({:?})[{:?}]", join!(", ", self.self_args()), join!(", ", self.scope()))?;
2038 Ok(())
2039 }
2040 }
2041
2042 impl Pretty for Path {
2043 fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2044 w!(cx, f, "{:?}", &self.loc)?;
2045 for field in &self.projection {
2046 w!(cx, f, ".{}", ^u32::from(*field))?;
2047 }
2048 Ok(())
2049 }
2050 }
2051
2052 impl Pretty for Loc {
2053 fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2054 match self {
2055 Loc::Local(local) => w!(cx, f, "{:?}", ^local),
2056 Loc::Var(var) => w!(cx, f, "{:?}", var),
2057 }
2058 }
2059 }
2060
2061 impl Pretty for BinOp {
2062 fn fmt(&self, _cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2063 match self {
2064 BinOp::Iff => w!(cx, f, "<=>"),
2065 BinOp::Imp => w!(cx, f, "=>"),
2066 BinOp::Or => w!(cx, f, "||"),
2067 BinOp::And => w!(cx, f, "&&"),
2068 BinOp::Eq => w!(cx, f, "=="),
2069 BinOp::Ne => w!(cx, f, "!="),
2070 BinOp::Gt(_) => w!(cx, f, ">"),
2071 BinOp::Ge(_) => w!(cx, f, ">="),
2072 BinOp::Lt(_) => w!(cx, f, "<"),
2073 BinOp::Le(_) => w!(cx, f, "<="),
2074 BinOp::Add(_) => w!(cx, f, "+"),
2075 BinOp::Sub(_) => w!(cx, f, "-"),
2076 BinOp::Mul(_) => w!(cx, f, "*"),
2077 BinOp::Div(_) => w!(cx, f, "/"),
2078 BinOp::Mod(_) => w!(cx, f, "mod"),
2079 BinOp::BitAnd(_) => w!(cx, f, "&"),
2080 BinOp::BitOr(_) => w!(cx, f, "|"),
2081 BinOp::BitXor(_) => w!(cx, f, "^"),
2082 BinOp::BitShl(_) => w!(cx, f, "<<"),
2083 BinOp::BitShr(_) => w!(cx, f, ">>"),
2084 }
2085 }
2086 }
2087
2088 impl Pretty for UnOp {
2089 fn fmt(&self, _cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2090 match self {
2091 UnOp::Not => w!(cx, f, "!"),
2092 UnOp::Neg => w!(cx, f, "-"),
2093 }
2094 }
2095 }
2096
2097 impl_debug_with_default_cx!(Expr, Loc, Path, Var, KVar, WKVar, Lambda, AliasReft);
2098
2099 impl PrettyNested for Lambda {
2100 fn fmt_nested(&self, cx: &PrettyCx) -> Result<NestedString, fmt::Error> {
2101 cx.nested_with_bound_vars("λ", self.body.vars(), None, |prefix| {
2103 let expr_d = self.body.skip_binder_ref().fmt_nested(cx)?;
2104 let text = format!("{}{}", prefix, expr_d.text);
2105 Ok(NestedString { text, children: expr_d.children, key: None })
2106 })
2107 }
2108 }
2109
2110 pub fn aggregate_nested(
2111 cx: &PrettyCx,
2112 ctor: &Ctor,
2113 flds: &[Expr],
2114 is_named: bool,
2115 ) -> Result<NestedString, fmt::Error> {
2116 let mut text =
2117 if is_named && ctor.is_enum() { format_cx!(cx, "{:?}", ctor) } else { "".to_string() };
2118 if flds.is_empty() {
2119 Ok(NestedString { text, children: None, key: None })
2121 } else if flds.len() == 1 {
2122 text += &flds[0].fmt_nested(cx)?.text;
2124 Ok(NestedString { text, children: None, key: None })
2125 } else {
2126 let keys = if let Some((def_id, variant_idx)) = ctor.def_id_and_variant()
2127 && let Some(adt_sort_def) = cx.adt_sort_def_of(def_id)
2128 {
2129 adt_sort_def
2130 .variant(variant_idx)
2131 .field_names()
2132 .iter()
2133 .map(|name| format!("{name}"))
2134 .collect_vec()
2135 } else if matches!(ctor, Ctor::RawPtr) {
2136 RawPtrField::iter()
2137 .map(|field| field.name().to_string())
2138 .collect_vec()
2139 } else {
2140 (0..flds.len()).map(|i| format!("arg{i}")).collect_vec()
2141 };
2142 text += "{..}";
2144 let mut children = vec![];
2145 for (key, fld) in iter::zip(keys, flds) {
2146 let fld_d = fld.fmt_nested(cx)?;
2147 children.push(NestedString { key: Some(key), ..fld_d });
2148 }
2149 Ok(NestedString { text, children: Some(children), key: None })
2150 }
2151 }
2152
2153 impl PrettyNested for Name {
2154 fn fmt_nested(&self, cx: &PrettyCx) -> Result<NestedString, fmt::Error> {
2155 let text = cx.pretty_var_env.get(&PrettyVar::Local(*self));
2156 Ok(NestedString { text, key: None, children: None })
2157 }
2158 }
2159
2160 impl PrettyNested for Expr {
2161 fn fmt_nested(&self, cx: &PrettyCx) -> Result<NestedString, fmt::Error> {
2162 let e = if cx.simplify_exprs {
2163 self.simplify(&SnapshotMap::default())
2164 } else {
2165 self.clone()
2166 };
2167 match e.kind() {
2168 ExprKind::Var(Var::Free(name)) => name.fmt_nested(cx),
2169 ExprKind::Var(..)
2170 | ExprKind::Local(..)
2171 | ExprKind::Constant(..)
2172 | ExprKind::ConstDefId(..)
2173 | ExprKind::Hole(..)
2174 | ExprKind::GlobalFunc(..)
2175 | ExprKind::InternalFunc(..) => debug_nested(cx, &e),
2176 ExprKind::WKVar(..) => debug_nested(cx, &e),
2177 ExprKind::KVar(kvar) => {
2178 let kv = format!("{:?}", kvar.kvid);
2179 let mut strs = vec![kv];
2180 for arg in &kvar.args {
2181 strs.push(arg.fmt_nested(cx)?.text);
2182 }
2183 let text = format!("##[{}]##", strs.join("##"));
2184 Ok(NestedString { text, children: None, key: None })
2185 }
2186 ExprKind::IfThenElse(p, e1, e2) => {
2187 let p_d = p.fmt_nested(cx)?;
2188 let e1_d = e1.fmt_nested(cx)?;
2189 let e2_d = e2.fmt_nested(cx)?;
2190 let text = format!("(if {} then {} else {})", p_d.text, e1_d.text, e2_d.text);
2191 let children = float_children(vec![p_d.children, e1_d.children, e2_d.children]);
2192 Ok(NestedString { text, children, key: None })
2193 }
2194 ExprKind::BinaryOp(op, e1, e2) => {
2195 let e1_d = e1.fmt_nested(cx)?;
2196 let e2_d = e2.fmt_nested(cx)?;
2197 let e1_text = if should_parenthesize(op, e1) {
2198 format!("({})", e1_d.text)
2199 } else {
2200 e1_d.text
2201 };
2202 let e2_text = if should_parenthesize(op, e2) {
2203 format!("({})", e2_d.text)
2204 } else {
2205 e2_d.text
2206 };
2207 let op_d = debug_nested(cx, op)?;
2208 let op_text = if matches!(op, BinOp::Div(_)) {
2209 op_d.text
2210 } else {
2211 format!(" {} ", op_d.text)
2212 };
2213 let text = format!("{e1_text}{op_text}{e2_text}");
2214 let children = float_children(vec![e1_d.children, e2_d.children]);
2215 Ok(NestedString { text, children, key: None })
2216 }
2217 ExprKind::UnaryOp(op, e) => {
2218 let e_d = e.fmt_nested(cx)?;
2219 let op_d = debug_nested(cx, op)?;
2220 let text = if e.is_atom() {
2221 format!("{}{}", op_d.text, e_d.text)
2222 } else {
2223 format!("{}({})", op_d.text, e_d.text)
2224 };
2225 Ok(NestedString { text, children: e_d.children, key: None })
2226 }
2227 ExprKind::FieldProj(e, proj) if let ExprKind::Ctor(_, _) = e.kind() => {
2228 e.proj_and_reduce(*proj).fmt_nested(cx)
2231 }
2232 ExprKind::FieldProj(e, proj) => {
2233 let e_d = e.fmt_nested(cx)?;
2234 let text = if e.is_atom() {
2235 format!("{}.{}", e_d.text, fmt_field_proj(cx, *proj))
2236 } else {
2237 format!("({}).{}", e_d.text, fmt_field_proj(cx, *proj))
2238 };
2239 Ok(NestedString { text, children: e_d.children, key: None })
2240 }
2241 ExprKind::Tuple(flds) => {
2242 let mut texts = vec![];
2243 let mut kidss = vec![];
2244 for e in flds {
2245 let e_d = e.fmt_nested(cx)?;
2246 texts.push(e_d.text);
2247 kidss.push(e_d.children);
2248 }
2249 let text = if let [e] = &texts[..] {
2250 format!("({e},)")
2251 } else {
2252 format!("({})", texts.join(", "))
2253 };
2254 let children = float_children(kidss);
2255 Ok(NestedString { text, children, key: None })
2256 }
2257 ExprKind::Ctor(ctor, flds) => aggregate_nested(cx, ctor, flds, true),
2258 ExprKind::IsCtor(def_id, variant_idx, idx) => {
2259 let text = format!("is::{:?}::{:?}( {:?} )", def_id, variant_idx, idx);
2260 Ok(NestedString { text, children: None, key: None })
2261 }
2262 ExprKind::PathProj(e, field) => {
2263 let e_d = e.fmt_nested(cx)?;
2264 let text = if e.is_atom() {
2265 format!("{}.{:?}", e_d.text, field)
2266 } else {
2267 format!("({}).{:?}", e_d.text, field)
2268 };
2269 Ok(NestedString { text, children: e_d.children, key: None })
2270 }
2271 ExprKind::Alias(alias, args) => {
2272 let mut texts = vec![];
2273 let mut kidss = vec![];
2274 for arg in args {
2275 let arg_d = arg.fmt_nested(cx)?;
2276 texts.push(arg_d.text);
2277 kidss.push(arg_d.children);
2278 }
2279 let text = format_cx!(cx, "{:?}({:?})", alias, texts.join(", "));
2280 let children = float_children(kidss);
2281 Ok(NestedString { text, children, key: None })
2282 }
2283 ExprKind::App(func, _, args) => {
2284 let func_d = func.fmt_nested(cx)?;
2285 let mut texts = vec![];
2286 let mut kidss = vec![func_d.children];
2287 for arg in args {
2288 let arg_d = arg.fmt_nested(cx)?;
2289 texts.push(arg_d.text);
2290 kidss.push(arg_d.children);
2291 }
2292 let text = if func.is_atom() {
2293 format!("{}({})", func_d.text, texts.join(", "))
2294 } else {
2295 format!("({})({})", func_d.text, texts.join(", "))
2296 };
2297 let children = float_children(kidss);
2298 Ok(NestedString { text, children, key: None })
2299 }
2300 ExprKind::Abs(lambda) => lambda.fmt_nested(cx),
2301 ExprKind::Let(init, body) => {
2302 cx.nested_with_bound_vars("let", body.vars(), None, |prefix| {
2304 let body = body.skip_binder_ref().fmt_nested(cx)?;
2305 let text = format!("{:?} {}{}", init, prefix, body.text);
2306 Ok(NestedString { text, children: body.children, key: None })
2307 })
2308 }
2309 ExprKind::Quant(kind, dom, body) => {
2310 let left = match kind {
2311 fhir::QuantKind::Forall => "∀",
2312 fhir::QuantKind::Exists => "∃",
2313 };
2314 let right = Some(format!(" {:?}", dom));
2315
2316 cx.nested_with_bound_vars(left, body.vars(), right, |all_str| {
2317 let expr_d = body.as_ref().skip_binder().fmt_nested(cx)?;
2318 let text = format!("{}{}", all_str, expr_d.text);
2319 Ok(NestedString { text, children: expr_d.children, key: None })
2320 })
2321 }
2322 }
2323 }
2324 }
2325}
2326
2327impl Expr {
2328 pub fn prettify(&self) -> Self {
2330 self.fold_constants()
2331 .push_negations()
2332 .simplify_arithmetic()
2333 .simplify_bounds()
2334 }
2335
2336 pub fn fold_constants(&self) -> Self {
2338 let span = self.span();
2339 match self.kind() {
2340 ExprKind::UnaryOp(op, a) => {
2341 let a_fold = a.fold_constants();
2342
2343 if let ExprKind::Constant(c) = a_fold.kind() {
2344 match (op, c) {
2345 (UnOp::Not, Constant::Bool(b)) => {
2346 return Expr::constant(Constant::Bool(!b)).at_opt(span);
2347 }
2348 (UnOp::Neg, Constant::Int(n)) => {
2349 return Expr::constant(Constant::Int(n.neg())).at_opt(span);
2350 }
2351 _ => {}
2352 }
2353 }
2354 Expr::unary_op(*op, a_fold).at_opt(span)
2355 }
2356
2357 ExprKind::BinaryOp(op, a, b) => {
2358 let a_fold = a.fold_constants();
2359 let b_fold = b.fold_constants();
2360
2361 if let (ExprKind::Constant(c1), ExprKind::Constant(c2)) =
2362 (a_fold.kind(), b_fold.kind())
2363 {
2364 if let Some(c3) = Expr::const_op(op, c1, c2) {
2366 return Expr::constant(c3).at_opt(span);
2367 }
2368
2369 if let (Constant::Int(n1), Constant::Int(n2)) = (c1, c2) {
2371 let result = match op {
2372 BinOp::Add(_) => n1.checked_add(n2),
2373 BinOp::Sub(_) => n1.checked_sub(n2),
2374 BinOp::Mul(_) => n1.checked_mul(n2),
2375 BinOp::Div(_) => n1.checked_div(n2),
2376 BinOp::Mod(_) => n1.checked_rem(n2),
2377 _ => None,
2378 };
2379
2380 if let Some(res) = result {
2381 return Expr::constant(Constant::Int(res)).at_opt(span);
2382 }
2383 }
2384 }
2385
2386 Expr::binary_op(op.clone(), a_fold, b_fold).at_opt(span)
2387 }
2388
2389 ExprKind::IfThenElse(p, e1, e2) => {
2390 let p_fold = p.fold_constants();
2391
2392 if let ExprKind::Constant(Constant::Bool(b)) = p_fold.kind() {
2394 if *b {
2395 return e1.fold_constants().at_opt(span);
2396 } else {
2397 return e2.fold_constants().at_opt(span);
2398 }
2399 }
2400
2401 Expr::ite(p_fold, e1.fold_constants(), e2.fold_constants()).at_opt(span)
2402 }
2403
2404 _ => self.clone(),
2407 }
2408 }
2409
2410 pub fn push_negations(&self) -> Self {
2412 let span = self.span();
2413 match self.kind() {
2414 ExprKind::UnaryOp(UnOp::Not, inner) => {
2415 match inner.kind() {
2416 ExprKind::UnaryOp(UnOp::Not, a) => a.push_negations().at_opt(span),
2418
2419 ExprKind::BinaryOp(BinOp::Le(s), a, b) => {
2421 Expr::binary_op(
2422 BinOp::Gt(s.clone()),
2423 a.push_negations(),
2424 b.push_negations(),
2425 )
2426 .at_opt(span)
2427 }
2428 ExprKind::BinaryOp(BinOp::Lt(s), a, b) => {
2429 Expr::binary_op(
2430 BinOp::Ge(s.clone()),
2431 a.push_negations(),
2432 b.push_negations(),
2433 )
2434 .at_opt(span)
2435 }
2436 ExprKind::BinaryOp(BinOp::Ge(s), a, b) => {
2437 Expr::binary_op(
2438 BinOp::Lt(s.clone()),
2439 a.push_negations(),
2440 b.push_negations(),
2441 )
2442 .at_opt(span)
2443 }
2444 ExprKind::BinaryOp(BinOp::Gt(s), a, b) => {
2445 Expr::binary_op(
2446 BinOp::Le(s.clone()),
2447 a.push_negations(),
2448 b.push_negations(),
2449 )
2450 .at_opt(span)
2451 }
2452
2453 ExprKind::BinaryOp(BinOp::Eq, a, b) => {
2455 Expr::binary_op(BinOp::Ne, a.push_negations(), b.push_negations())
2456 .at_opt(span)
2457 }
2458 ExprKind::BinaryOp(BinOp::Ne, a, b) => {
2459 Expr::binary_op(BinOp::Eq, a.push_negations(), b.push_negations())
2460 .at_opt(span)
2461 }
2462
2463 ExprKind::BinaryOp(BinOp::Or, a, b) => {
2465 Expr::binary_op(
2466 BinOp::And,
2467 a.not().push_negations(),
2468 b.not().push_negations(),
2469 )
2470 .at_opt(span)
2471 }
2472 ExprKind::BinaryOp(BinOp::And, a, b) => {
2473 Expr::binary_op(
2474 BinOp::Or,
2475 a.not().push_negations(),
2476 b.not().push_negations(),
2477 )
2478 .at_opt(span)
2479 }
2480
2481 _ => Expr::unary_op(UnOp::Not, inner.push_negations()).at_opt(span),
2483 }
2484 }
2485 ExprKind::BinaryOp(op, a, b) => {
2486 Expr::binary_op(op.clone(), a.push_negations(), b.push_negations()).at_opt(span)
2487 }
2488 ExprKind::UnaryOp(op, a) => Expr::unary_op(*op, a.push_negations()).at_opt(span),
2489 ExprKind::IfThenElse(p, e1, e2) => {
2490 Expr::ite(p.push_negations(), e1.push_negations(), e2.push_negations()).at_opt(span)
2491 }
2492 _ => self.clone(),
2493 }
2494 }
2495
2496 pub fn simplify_arithmetic(&self) -> Self {
2498 let span = self.span();
2499 match self.kind() {
2500 ExprKind::BinaryOp(BinOp::Mul(s), a, b) => {
2501 let a_simp = a.simplify_arithmetic();
2502 let b_simp = b.simplify_arithmetic();
2503
2504 let is_minus_one = |e: &Expr| matches!(e.kind(), ExprKind::Constant(c) if *c == Constant::from(-1));
2505
2506 if is_minus_one(&b_simp) {
2507 return a_simp.neg().at_opt(span);
2508 }
2509 if is_minus_one(&a_simp) {
2510 return b_simp.neg().at_opt(span);
2511 }
2512
2513 Expr::binary_op(BinOp::Mul(s.clone()), a_simp, b_simp).at_opt(span)
2514 }
2515 ExprKind::BinaryOp(BinOp::Add(s), a, b) => {
2516 let a_simp = a.simplify_arithmetic();
2517 let b_simp = b.simplify_arithmetic();
2518
2519 if let ExprKind::UnaryOp(UnOp::Neg, x) = a_simp.kind() {
2520 return Expr::binary_op(BinOp::Sub(s.clone()), b_simp, x.clone()).at_opt(span);
2521 }
2522 if let ExprKind::UnaryOp(UnOp::Neg, y) = b_simp.kind() {
2523 return Expr::binary_op(BinOp::Sub(s.clone()), a_simp, y.clone()).at_opt(span);
2524 }
2525
2526 Expr::binary_op(BinOp::Add(s.clone()), a_simp, b_simp).at_opt(span)
2527 }
2528 ExprKind::BinaryOp(op, a, b) => {
2529 Expr::binary_op(op.clone(), a.simplify_arithmetic(), b.simplify_arithmetic())
2530 .at_opt(span)
2531 }
2532 ExprKind::UnaryOp(op, a) => Expr::unary_op(*op, a.simplify_arithmetic()).at_opt(span),
2533 ExprKind::IfThenElse(p, e1, e2) => {
2534 Expr::ite(
2535 p.simplify_arithmetic(),
2536 e1.simplify_arithmetic(),
2537 e2.simplify_arithmetic(),
2538 )
2539 .at_opt(span)
2540 }
2541 _ => self.clone(),
2542 }
2543 }
2544
2545 pub fn simplify_bounds(&self) -> Self {
2547 let span = self.span();
2548 match self.kind() {
2549 ExprKind::BinaryOp(op, a, b) => {
2550 let a_simp = a.simplify_bounds();
2551 let b_simp = b.simplify_bounds();
2552
2553 let is_minus_one = |e: &Expr| matches!(e.kind(), ExprKind::Constant(c) if *c == Constant::from(-1));
2554 let is_zero =
2555 |e: &Expr| matches!(e.kind(), ExprKind::Constant(c) if *c == Constant::from(0));
2556
2557 match op {
2559 BinOp::Gt(Sort::Int) => {
2560 if is_minus_one(&b_simp) {
2562 return Expr::binary_op(BinOp::Ge(Sort::Int), a_simp, Expr::zero())
2563 .at_opt(span)
2564 .simplify_bounds();
2565 }
2566 if is_zero(&b_simp)
2568 && let ExprKind::BinaryOp(BinOp::Sub(s_sub), x, y) = a_simp.kind()
2569 {
2570 return Expr::binary_op(BinOp::Gt(s_sub.clone()), x.clone(), y.clone())
2571 .at_opt(span);
2572 }
2573 }
2574 BinOp::Ge(Sort::Int) => {
2575 if is_zero(&b_simp)
2577 && let ExprKind::BinaryOp(BinOp::Sub(s_sub), x, y) = a_simp.kind()
2578 {
2579 return Expr::binary_op(BinOp::Ge(s_sub.clone()), x.clone(), y.clone())
2580 .at_opt(span);
2581 }
2582 }
2583 BinOp::Lt(Sort::Int) => {
2584 if is_zero(&b_simp)
2586 && let ExprKind::BinaryOp(BinOp::Sub(s_sub), x, y) = a_simp.kind()
2587 {
2588 return Expr::binary_op(BinOp::Lt(s_sub.clone()), x.clone(), y.clone())
2589 .at_opt(span);
2590 }
2591 }
2592 BinOp::Le(Sort::Int) => {
2593 if is_minus_one(&b_simp) {
2595 return Expr::binary_op(BinOp::Lt(Sort::Int), a_simp, Expr::zero())
2596 .at_opt(span)
2597 .simplify_bounds();
2598 }
2599 if is_zero(&b_simp)
2601 && let ExprKind::BinaryOp(BinOp::Sub(s_sub), x, y) = a_simp.kind()
2602 {
2603 return Expr::binary_op(BinOp::Le(s_sub.clone()), x.clone(), y.clone())
2604 .at_opt(span);
2605 }
2606 }
2607 _ => {}
2608 }
2609
2610 Expr::binary_op(op.clone(), a_simp, b_simp).at_opt(span)
2611 }
2612 ExprKind::UnaryOp(op, a) => Expr::unary_op(*op, a.simplify_bounds()).at_opt(span),
2613 ExprKind::IfThenElse(p, e1, e2) => {
2614 Expr::ite(p.simplify_bounds(), e1.simplify_bounds(), e2.simplify_bounds())
2615 .at_opt(span)
2616 }
2617 _ => self.clone(),
2618 }
2619 }
2620}