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::Unevaluated(_) => bug!("unexpected `ConstKind::Unevaluated`"),
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 visit_conj<'a>(&'a self, mut f: impl FnMut(&'a Expr)) {
617 fn go<'a>(e: &'a Expr, f: &mut impl FnMut(&'a Expr)) {
618 if let ExprKind::BinaryOp(BinOp::And, e1, e2) = e.kind() {
619 go(e1, f);
620 go(e2, f);
621 } else {
622 f(e);
623 }
624 }
625 go(self, &mut f);
626 }
627
628 pub fn flatten_conjs(&self) -> Vec<&Expr> {
629 let mut vec = vec![];
630 self.visit_conj(|e| vec.push(e));
631 vec
632 }
633
634 pub fn has_evars(&self) -> bool {
635 struct HasEvars;
636
637 impl TypeVisitor for HasEvars {
638 type BreakTy = ();
639 fn visit_expr(&mut self, expr: &Expr) -> ControlFlow<Self::BreakTy> {
640 if let ExprKind::Var(Var::EVar(_)) = expr.kind() {
641 ControlFlow::Break(())
642 } else {
643 expr.super_visit_with(self)
644 }
645 }
646 }
647
648 self.visit_with(&mut HasEvars).is_break()
649 }
650
651 pub fn erase_spans(&self) -> Expr {
652 struct SpanEraser;
653 impl TypeFolder for SpanEraser {
654 fn fold_expr(&mut self, e: &Expr) -> Expr {
655 e.super_fold_with(self).at_opt(None)
656 }
657 }
658 self.fold_with(&mut SpanEraser)
659 }
660
661 pub fn erase_bound_reft_kind(&self) -> Expr {
669 struct BoundReftKindEraser;
670 impl TypeFolder for BoundReftKindEraser {
671 fn fold_expr(&mut self, expr: &Expr) -> Expr {
672 if let ExprKind::Var(Var::Bound(
673 db_index,
674 BoundReft { var, kind: BoundReftKind::Named(_) },
675 )) = expr.kind()
676 {
677 Expr::bvar(*db_index, *var, BoundReftKind::Anon)
678 } else {
679 expr.super_fold_with(self)
680 }
681 }
682 }
683 self.fold_with(&mut BoundReftKindEraser)
684 }
685
686 pub fn erase_metadata(&self) -> Expr {
687 self.erase_spans().erase_bound_reft_kind()
688 }
689
690 pub fn expand_bin_rels(&self) -> Expr {
704 struct BinRelExpander;
705 impl BinRelExpander {
706 fn expand_bin_rel(&mut self, sort: &Sort, rel: &BinOp, e1: &Expr, e2: &Expr) -> Expr {
707 match sort {
708 Sort::Tuple(sorts) => {
709 let arity = sorts.len();
710 self.apply_bin_rel_rec(sorts, rel, e1, e2, |field| {
711 FieldProj::Tuple { arity, field }
712 })
713 }
714 Sort::App(SortCtor::Adt(sort_def), args)
715 if let Some(variant) = sort_def.opt_struct_variant() =>
716 {
717 let def_id = sort_def.did();
718 let sorts = variant.field_sorts(args);
719 self.apply_bin_rel_rec(&sorts, rel, e1, e2, |field| {
720 FieldProj::Adt { def_id, field }
721 })
722 }
723 _ => {
724 Expr::binary_op(
725 rel.clone(),
726 e1.super_fold_with(self),
727 e2.super_fold_with(self),
728 )
729 }
730 }
731 }
732 fn apply_bin_rel_rec(
734 &mut self,
735 sorts: &[Sort],
736 rel: &BinOp,
737 e1: &Expr,
738 e2: &Expr,
739 mk_proj: impl Fn(u32) -> FieldProj,
740 ) -> Expr {
741 Expr::and_from_iter(sorts.iter().enumerate().map(|(idx, s)| {
742 let proj = mk_proj(idx as u32);
743 let e1 = e1.proj_and_reduce(proj);
744 let e2 = e2.proj_and_reduce(proj);
745 self.expand_bin_rel(s, rel, &e1, &e2)
746 }))
747 }
748 }
749 impl TypeFolder for BinRelExpander {
750 fn fold_expr(&mut self, expr: &Expr) -> Expr {
751 if let ExprKind::BinaryOp(
752 rel @ (BinOp::Le(sort) | BinOp::Lt(sort) | BinOp::Ge(sort) | BinOp::Gt(sort)),
753 e1,
754 e2,
755 ) = expr.kind()
756 {
757 self.expand_bin_rel(sort, rel, e1, e2)
758 } else {
759 expr.super_fold_with(self)
760 }
761 }
762 }
763
764 let mut expander = BinRelExpander {};
765 self.fold_with(&mut expander)
766 }
767
768 pub fn eta_reduce_projs(&self) -> Self {
776 struct EtaReducer;
777 impl TypeFolder for EtaReducer {
778 fn fold_expr(&mut self, expr: &Expr) -> Expr {
779 match expr.kind() {
780 ExprKind::Tuple(subexprs) => {
781 let new_subexprs = subexprs
782 .iter()
783 .map(|subexpr| subexpr.fold_with(self))
784 .collect_vec();
785 if let Some(ExprKind::FieldProj(
786 e_inner,
787 FieldProj::Tuple { arity: _, field: 0 },
788 )) = subexprs.first().map(|e| e.kind())
789 && new_subexprs[1..].iter().zip(1..).all(|(other_e, i)| {
790 if let ExprKind::FieldProj(
791 other_e_inner,
792 FieldProj::Tuple { arity: _, field },
793 ) = other_e.kind()
794 {
795 field == &i && &e_inner.erase_metadata() == other_e_inner
796 } else {
797 false
798 }
799 })
800 {
801 e_inner.clone()
802 } else {
803 expr.clone()
804 }
805 }
806 ExprKind::Ctor(_ctor, subexprs) => {
807 let new_subexprs = subexprs
808 .iter()
809 .map(|subexpr| subexpr.fold_with(self))
810 .collect_vec();
811 if let Some(ExprKind::FieldProj(
812 e_inner,
813 FieldProj::Adt { def_id: _, field: 0 },
814 )) = subexprs.first().map(|e| e.kind())
815 && new_subexprs[1..].iter().zip(1..).all(|(other_e, i)| {
816 if let ExprKind::FieldProj(
817 other_e_inner,
818 FieldProj::Adt { def_id: _, field },
819 ) = other_e.kind()
820 {
821 field == &i && &e_inner.erase_metadata() == other_e_inner
822 } else {
823 false
824 }
825 })
826 {
827 e_inner.clone()
828 } else {
829 expr.clone()
830 }
831 }
832 _ => expr.super_fold_with(self),
833 }
834 }
835 }
836 self.fold_with(&mut EtaReducer)
837 }
838}
839
840#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Debug)]
841pub struct ESpan {
842 pub span: Span,
844 pub base: Option<Span>,
846}
847
848impl ESpan {
849 pub fn new(span: Span) -> Self {
850 Self { span, base: None }
851 }
852
853 pub fn with_base(&self, espan: ESpan) -> Self {
854 Self { span: self.span, base: Some(espan.span) }
855 }
856}
857
858#[derive(
859 Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Debug, TypeFoldable, TypeVisitable,
860)]
861pub enum BinOp {
862 Iff,
863 Imp,
864 Or,
865 And,
866 Eq,
867 Ne,
868 Gt(Sort),
869 Ge(Sort),
870 Lt(Sort),
871 Le(Sort),
872 Add(Sort),
873 Sub(Sort),
874 Mul(Sort),
875 Div(Sort),
876 Mod(Sort),
877 BitAnd(Sort),
878 BitOr(Sort),
879 BitXor(Sort),
880 BitShl(Sort),
881 BitShr(Sort),
882}
883
884#[derive(Clone, Copy, PartialEq, Eq, Hash, Encodable, Debug, Decodable)]
885pub enum UnOp {
886 Not,
887 Neg,
888}
889
890#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, TyEncodable, TyDecodable)]
891pub enum Ctor {
892 Struct(DefId),
894 Enum(DefId, VariantIdx),
896 RawPtr,
898}
899
900impl Ctor {
901 fn is_enum(&self) -> bool {
902 matches!(self, Self::Enum(..))
903 }
904
905 pub fn def_id_and_variant(&self) -> Option<(DefId, VariantIdx)> {
906 match self {
907 Self::Struct(def_id) => Some((*def_id, FIRST_VARIANT)),
908 Self::Enum(def_id, variant_idx) => Some((*def_id, *variant_idx)),
909 Self::RawPtr => None,
910 }
911 }
912}
913
914#[derive(Debug, Clone, TyEncodable, TyDecodable, PartialEq, Eq, Hash)]
928pub enum InternalFuncKind {
929 Val(BinOp),
931 Rel(BinOp),
933 Cast,
935}
936
937#[derive(Debug, Clone, TyEncodable, TyDecodable, PartialEq, Eq, Hash)]
938pub enum SpecFuncKind {
939 Thy(liquid_fixpoint::ThyFunc),
941 Def(FluxDefId),
943}
944
945#[derive(
946 Clone, PartialEq, Eq, Hash, TyEncodable, Debug, TyDecodable, TypeVisitable, TypeFoldable,
947)]
948pub enum QuantDom {
949 Bounded { start: usize, end: usize },
950 Unbounded,
951}
952
953#[derive(Clone, PartialEq, Eq, Hash, TyEncodable, Debug, TyDecodable)]
954pub enum ExprKind {
955 Var(Var),
956 Local(Local),
957 Constant(Constant),
958 ConstDefId(DefId),
960 BinaryOp(BinOp, Expr, Expr),
961 GlobalFunc(SpecFuncKind),
962 InternalFunc(InternalFuncKind),
963 UnaryOp(UnOp, Expr),
964 FieldProj(Expr, FieldProj),
965 Ctor(Ctor, List<Expr>),
967 Tuple(List<Expr>),
968 PathProj(Expr, FieldIdx),
969 IfThenElse(Expr, Expr, Expr),
970 KVar(KVar),
971 WKVar(WKVar),
972 Alias(AliasReft, List<Expr>),
973 Let(Expr, Binder<Expr>),
974 App(Expr, List<SortArg>, List<Expr>),
980 Abs(Lambda),
990
991 Quant(fhir::QuantKind, QuantDom, Binder<Expr>),
993 Hole(HoleKind),
1007 IsCtor(DefId, VariantIdx, Expr),
1009}
1010
1011impl ExprKind {
1012 fn intern(self) -> Expr {
1013 Expr { kind: Interned::new(self), espan: None }
1014 }
1015}
1016
1017#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Debug)]
1018pub enum AggregateKind {
1019 Tuple(usize),
1020 Adt(DefId),
1021}
1022
1023#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Debug)]
1024pub enum FieldProj {
1025 Tuple { arity: usize, field: u32 },
1026 Adt { def_id: DefId, field: u32 },
1027 RawPtr { field: RawPtrField },
1028}
1029
1030#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Debug)]
1031pub enum RawPtrField {
1032 Base,
1033 Addr,
1034 Size,
1035}
1036
1037struct RawPtrFieldData {
1038 field: RawPtrField,
1039 index: u32,
1040 name: &'static str,
1041 sort: Sort,
1042}
1043
1044impl FieldProj {
1045 pub fn arity(&self, genv: GlobalEnv) -> QueryResult<usize> {
1046 match self {
1047 FieldProj::Tuple { arity, .. } => Ok(*arity),
1048 FieldProj::Adt { def_id, .. } => {
1049 Ok(genv.adt_sort_def_of(*def_id)?.struct_variant().fields())
1050 }
1051 FieldProj::RawPtr { .. } => Ok(RawPtrField::arity()),
1052 }
1053 }
1054
1055 pub fn field_idx(&self) -> u32 {
1056 match self {
1057 FieldProj::Tuple { field, .. } | FieldProj::Adt { field, .. } => *field,
1058 FieldProj::RawPtr { field } => field.index(),
1059 }
1060 }
1061}
1062
1063impl RawPtrField {
1064 const DATA: [RawPtrFieldData; 3] = [
1065 RawPtrFieldData { field: Self::Base, index: 0, name: "base", sort: Sort::Int },
1066 RawPtrFieldData { field: Self::Addr, index: 1, name: "addr", sort: Sort::Int },
1067 RawPtrFieldData { field: Self::Size, index: 2, name: "size", sort: Sort::Int },
1068 ];
1069
1070 pub fn iter() -> impl ExactSizeIterator<Item = Self> {
1071 Self::DATA.iter().map(|data| data.field)
1072 }
1073
1074 pub fn arity() -> usize {
1075 Self::DATA.len()
1076 }
1077
1078 fn data(self) -> &'static RawPtrFieldData {
1079 Self::DATA.iter().find(|data| data.field == self).unwrap()
1080 }
1081
1082 pub fn from_name(name: Symbol) -> Option<Self> {
1083 Self::DATA
1084 .iter()
1085 .find(|data| data.name == name.as_str())
1086 .map(|data| data.field)
1087 }
1088
1089 pub fn from_index(index: u32) -> Option<Self> {
1090 Self::DATA
1091 .iter()
1092 .find(|data| data.index == index)
1093 .map(|data| data.field)
1094 }
1095
1096 pub fn sort(self) -> Sort {
1097 self.data().sort.clone()
1098 }
1099
1100 pub fn index(self) -> u32 {
1101 self.data().index
1102 }
1103
1104 pub fn name(self) -> &'static str {
1105 self.data().name
1106 }
1107
1108 pub fn symbol(self) -> Symbol {
1109 match self {
1110 Self::Base => sym::base,
1111 Self::Addr => sym::addr,
1112 Self::Size => rustc_span::sym::size,
1113 }
1114 }
1115}
1116
1117#[derive(
1123 Debug, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, TypeFoldable, TypeVisitable,
1124)]
1125pub enum HoleKind {
1126 Pred,
1131 Expr(Sort),
1138}
1139
1140#[derive(Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, TypeVisitable, TypeFoldable)]
1145pub struct KVar {
1146 pub kvid: KVid,
1147 pub self_args: usize,
1149 pub args: List<Expr>,
1152}
1153
1154#[derive(
1155 Debug, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, TypeVisitable, TypeFoldable,
1156)]
1157pub struct WKVid {
1158 pub parent_fn: DefId,
1161 pub id: KVid,
1164}
1165
1166impl WKVid {
1167 pub fn new(parent_fn: DefId, id: KVid) -> Self {
1168 Self { parent_fn, id }
1169 }
1170}
1171
1172#[derive(Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, TypeVisitable, TypeFoldable)]
1177pub struct WKVar {
1178 pub wkvid: WKVid,
1179 pub self_args: usize,
1213 pub args: List<Expr>,
1215}
1216
1217#[derive(Clone, Debug, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Encodable, Decodable)]
1218pub struct EarlyReftParam {
1219 pub index: u32,
1220 pub name: Symbol,
1221}
1222
1223#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Encodable, Decodable, Debug)]
1224pub struct BoundReft {
1225 pub var: BoundVar,
1226 pub kind: BoundReftKind,
1227}
1228
1229#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, TyEncodable, TyDecodable)]
1230pub enum Var {
1231 Free(Name),
1232 Bound(DebruijnIndex, BoundReft),
1233 EarlyParam(EarlyReftParam),
1234 EVar(EVid),
1235 ConstGeneric(ParamConst),
1236}
1237
1238#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord, TyEncodable, TyDecodable)]
1239pub struct Path {
1240 pub loc: Loc,
1241 projection: List<FieldIdx>,
1242}
1243
1244#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, TyEncodable, TyDecodable)]
1245pub enum Loc {
1246 Local(Local),
1247 Var(Var),
1248}
1249
1250newtype_index! {
1251 #[debug_format = "?{}e"]
1253 #[orderable]
1254 #[encodable]
1255 pub struct EVid {}
1256}
1257
1258newtype_index! {
1259 #[debug_format = "$k{}"]
1260 #[encodable]
1261 pub struct KVid {}
1262}
1263
1264newtype_index! {
1265 #[debug_format = "a{}"]
1266 #[orderable]
1267 #[encodable]
1268 pub struct Name {}
1269}
1270
1271#[derive(Copy, Debug, Clone)]
1272pub enum NameProvenance {
1273 Unknown,
1274 UnfoldBoundReft(BoundReftKind),
1275}
1276
1277impl NameProvenance {
1278 pub fn opt_symbol(&self) -> Option<Symbol> {
1279 match &self {
1280 NameProvenance::UnfoldBoundReft(BoundReftKind::Named(name)) => Some(*name),
1281 _ => None,
1282 }
1283 }
1284}
1285
1286#[derive(PartialEq, Eq, Hash, Debug)]
1287pub enum PrettyVar<V> {
1288 Local(V),
1289 Param(EarlyReftParam),
1290}
1291
1292impl<V: Copy + Into<usize>> PrettyVar<V> {
1293 pub fn as_subscript(&self) -> String {
1294 let idx = match self {
1295 PrettyVar::Local(v) => (*v).into(),
1296 PrettyVar::Param(p) => p.index as usize,
1297 };
1298 as_subscript(idx)
1299 }
1300}
1301
1302pub struct PrettyMap<V: Eq + Hash> {
1303 map: UnordMap<PrettyVar<V>, String>,
1304 count: UnordMap<Symbol, usize>,
1305}
1306
1307impl<V: Eq + Hash + Copy + Into<usize>> PrettyMap<V> {
1308 pub fn new() -> Self {
1309 PrettyMap { map: UnordMap::default(), count: UnordMap::default() }
1310 }
1311
1312 pub fn set(&mut self, var: PrettyVar<V>, prefix: Option<Symbol>) -> String {
1313 if let Some(symbol) = self.map.get(&var) {
1315 return symbol.clone();
1316 }
1317 let symbol = if let Some(prefix) = prefix {
1319 let index = self.count.entry(prefix).or_insert(0);
1320 let symbol = format!("{}{}", prefix, as_subscript(*index));
1321 *index += 1;
1322 symbol
1323 } else {
1324 format!("a'{}", var.as_subscript())
1325 };
1326 self.map.insert(var, symbol.clone());
1327 symbol
1328 }
1329
1330 pub fn get(&self, key: &PrettyVar<V>) -> String {
1331 match self.map.get(key) {
1332 Some(s) => s.clone(),
1333 None => format!("a'{}", key.as_subscript()),
1334 }
1335 }
1336}
1337
1338impl KVar {
1339 pub fn new(kvid: KVid, self_args: usize, args: Vec<Expr>) -> Self {
1340 KVar { kvid, self_args, args: List::from_vec(args) }
1341 }
1342
1343 fn self_args(&self) -> &[Expr] {
1344 &self.args[..self.self_args]
1345 }
1346
1347 fn scope(&self) -> &[Expr] {
1348 &self.args[self.self_args..]
1349 }
1350}
1351
1352impl WKVar {
1353 fn self_args(&self) -> &[Expr] {
1354 &self.args[..self.self_args]
1355 }
1356
1357 fn scope(&self) -> &[Expr] {
1358 &self.args[self.self_args..]
1359 }
1360}
1361
1362impl Var {
1363 pub fn to_expr(&self) -> Expr {
1364 Expr::var(*self)
1365 }
1366
1367 pub fn shift_in(&self, amount: u32) -> Self {
1368 match self {
1369 Var::Bound(idx, breft) => Var::Bound(idx.shifted_in(amount), *breft),
1370 _ => *self,
1371 }
1372 }
1373
1374 pub fn shift_out(&self, amount: u32) -> Self {
1375 match self {
1376 Var::Bound(idx, breft) => Var::Bound(idx.shifted_out(amount), *breft),
1377 _ => *self,
1378 }
1379 }
1380}
1381
1382impl Path {
1383 pub fn new(loc: Loc, projection: impl Into<List<FieldIdx>>) -> Path {
1384 Path { loc, projection: projection.into() }
1385 }
1386
1387 pub fn projection(&self) -> &[FieldIdx] {
1388 &self.projection[..]
1389 }
1390
1391 pub fn to_expr(&self) -> Expr {
1392 self.projection
1393 .iter()
1394 .fold(self.loc.to_expr(), |e, f| Expr::path_proj(e, *f))
1395 }
1396
1397 pub fn to_loc(&self) -> Option<Loc> {
1398 if self.projection.is_empty() { Some(self.loc) } else { None }
1399 }
1400}
1401
1402impl Loc {
1403 pub fn to_expr(&self) -> Expr {
1404 match self {
1405 Loc::Local(local) => Expr::local(*local),
1406 Loc::Var(var) => Expr::var(*var),
1407 }
1408 }
1409}
1410
1411macro_rules! impl_ops {
1412 ($($op:ident: $method:ident),*) => {$(
1413 impl<Rhs> std::ops::$op<Rhs> for Expr
1414 where
1415 Rhs: Into<Expr>,
1416 {
1417 type Output = Expr;
1418
1419 fn $method(self, rhs: Rhs) -> Self::Output {
1420 let sort = crate::rty::Sort::Int;
1421 Expr::binary_op(BinOp::$op(sort), self, rhs)
1422 }
1423 }
1424
1425 impl<Rhs> std::ops::$op<Rhs> for &Expr
1426 where
1427 Rhs: Into<Expr>,
1428 {
1429 type Output = Expr;
1430
1431 fn $method(self, rhs: Rhs) -> Self::Output {
1432 let sort = crate::rty::Sort::Int;
1433 Expr::binary_op(BinOp::$op(sort), self, rhs)
1434 }
1435 }
1436 )*};
1437}
1438impl_ops!(Add: add, Sub: sub, Mul: mul, Div: div);
1439
1440impl From<i32> for Expr {
1441 fn from(value: i32) -> Self {
1442 Expr::constant(Constant::from(value))
1443 }
1444}
1445
1446impl From<&Expr> for Expr {
1447 fn from(e: &Expr) -> Self {
1448 e.clone()
1449 }
1450}
1451
1452impl From<Path> for Expr {
1453 fn from(path: Path) -> Self {
1454 path.to_expr()
1455 }
1456}
1457
1458impl From<Name> for Expr {
1459 fn from(name: Name) -> Self {
1460 Expr::fvar(name)
1461 }
1462}
1463
1464impl From<Var> for Expr {
1465 fn from(var: Var) -> Self {
1466 Expr::var(var)
1467 }
1468}
1469
1470impl From<SpecFuncKind> for Expr {
1471 fn from(kind: SpecFuncKind) -> Self {
1472 Expr::global_func(kind)
1473 }
1474}
1475
1476impl From<InternalFuncKind> for Expr {
1477 fn from(kind: InternalFuncKind) -> Self {
1478 Expr::internal_func(kind)
1479 }
1480}
1481
1482impl From<Loc> for Path {
1483 fn from(loc: Loc) -> Self {
1484 Path::new(loc, vec![])
1485 }
1486}
1487
1488impl From<Name> for Loc {
1489 fn from(name: Name) -> Self {
1490 Loc::Var(Var::Free(name))
1491 }
1492}
1493
1494impl From<Local> for Loc {
1495 fn from(local: Local) -> Self {
1496 Loc::Local(local)
1497 }
1498}
1499
1500#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Encodable, Decodable)]
1501pub struct Real(pub Symbol);
1502
1503#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Encodable, Decodable)]
1504pub enum Constant {
1505 Int(BigInt),
1506 Real(Real),
1507 Bool(bool),
1508 Str(Symbol),
1509 Char(char),
1510 BitVec(u128, u32),
1511}
1512
1513impl Constant {
1514 pub const ZERO: Constant = Constant::Int(BigInt::ZERO);
1515 pub const ONE: Constant = Constant::Int(BigInt::ONE);
1516 pub const TRUE: Constant = Constant::Bool(true);
1517
1518 fn to_bool(self) -> Option<bool> {
1519 match self {
1520 Constant::Bool(b) => Some(b),
1521 _ => None,
1522 }
1523 }
1524
1525 fn to_int(self) -> Option<BigInt> {
1526 match self {
1527 Constant::Int(n) => Some(n),
1528 _ => None,
1529 }
1530 }
1531
1532 pub fn iff(&self, other: &Constant) -> Option<Constant> {
1533 let b1 = self.to_bool()?;
1534 let b2 = other.to_bool()?;
1535 Some(Constant::Bool(b1 == b2))
1536 }
1537
1538 pub fn imp(&self, other: &Constant) -> Option<Constant> {
1539 let b1 = self.to_bool()?;
1540 let b2 = other.to_bool()?;
1541 Some(Constant::Bool(!b1 || b2))
1542 }
1543
1544 pub fn or(&self, other: &Constant) -> Option<Constant> {
1545 let b1 = self.to_bool()?;
1546 let b2 = other.to_bool()?;
1547 Some(Constant::Bool(b1 || b2))
1548 }
1549
1550 pub fn and(&self, other: &Constant) -> Option<Constant> {
1551 let b1 = self.to_bool()?;
1552 let b2 = other.to_bool()?;
1553 Some(Constant::Bool(b1 && b2))
1554 }
1555
1556 pub fn eq(&self, other: &Constant) -> Constant {
1557 Constant::Bool(*self == *other)
1558 }
1559
1560 pub fn ne(&self, other: &Constant) -> Constant {
1561 Constant::Bool(*self != *other)
1562 }
1563
1564 pub fn gt(&self, other: &Constant) -> Option<Constant> {
1565 let n1 = self.to_int()?;
1566 let n2 = other.to_int()?;
1567 Some(Constant::Bool(n1 > n2))
1568 }
1569
1570 pub fn ge(&self, other: &Constant) -> Option<Constant> {
1571 let n1 = self.to_int()?;
1572 let n2 = other.to_int()?;
1573 Some(Constant::Bool(n1 >= n2))
1574 }
1575
1576 pub fn from_scalar_int<'tcx, T>(tcx: TyCtxt<'tcx>, scalar: ScalarInt, t: &T) -> Option<Self>
1577 where
1578 T: ToRustc<'tcx, T = rustc_middle::ty::Ty<'tcx>>,
1579 {
1580 use rustc_middle::ty::TyKind;
1581 let ty = t.to_rustc(tcx);
1582 match ty.kind() {
1583 TyKind::Int(int_ty) => Some(Constant::from(scalar_to_int(tcx, scalar, *int_ty))),
1584 TyKind::Uint(uint_ty) => Some(Constant::from(scalar_to_uint(tcx, scalar, *uint_ty))),
1585 TyKind::Bool => {
1586 let b = scalar_to_bits(tcx, scalar, ty)?;
1587 Some(Constant::Bool(b != 0))
1588 }
1589 TyKind::Char => {
1590 let b = scalar_to_bits(tcx, scalar, ty)?;
1591 Some(Constant::Char(char::from_u32(b as u32)?))
1592 }
1593 _ => bug!(),
1594 }
1595 }
1596
1597 pub fn int_min(bit_width: u32) -> Constant {
1599 Constant::Int(BigInt::int_min(bit_width))
1600 }
1601
1602 pub fn int_max(bit_width: u32) -> Constant {
1604 Constant::Int(BigInt::int_max(bit_width))
1605 }
1606
1607 pub fn uint_max(bit_width: u32) -> Constant {
1609 Constant::Int(BigInt::uint_max(bit_width))
1610 }
1611}
1612
1613impl From<i32> for Constant {
1614 fn from(c: i32) -> Self {
1615 Constant::Int(c.into())
1616 }
1617}
1618
1619impl From<usize> for Constant {
1620 fn from(u: usize) -> Self {
1621 Constant::Int(u.into())
1622 }
1623}
1624
1625impl From<u32> for Constant {
1626 fn from(c: u32) -> Self {
1627 Constant::Int(c.into())
1628 }
1629}
1630
1631impl From<u64> for Constant {
1632 fn from(c: u64) -> Self {
1633 Constant::Int(c.into())
1634 }
1635}
1636
1637impl From<u128> for Constant {
1638 fn from(c: u128) -> Self {
1639 Constant::Int(c.into())
1640 }
1641}
1642
1643impl From<i128> for Constant {
1644 fn from(c: i128) -> Self {
1645 Constant::Int(c.into())
1646 }
1647}
1648
1649impl From<bool> for Constant {
1650 fn from(b: bool) -> Self {
1651 Constant::Bool(b)
1652 }
1653}
1654
1655impl From<Symbol> for Constant {
1656 fn from(s: Symbol) -> Self {
1657 Constant::Str(s)
1658 }
1659}
1660
1661impl From<char> for Constant {
1662 fn from(c: char) -> Self {
1663 Constant::Char(c)
1664 }
1665}
1666
1667impl_internable!(ExprKind);
1668impl_slice_internable!(Expr, KVar);
1669
1670#[derive(Debug)]
1671pub struct FieldBind<T> {
1672 pub name: Symbol,
1673 pub value: T,
1674}
1675
1676impl<T: Pretty> Pretty for FieldBind<T> {
1677 fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1678 w!(cx, f, "{}: {:?}", ^self.name, &self.value)
1679 }
1680}
1681
1682pub(crate) mod pretty {
1683
1684 use flux_rustc_bridge::def_id_to_string;
1685
1686 use super::*;
1687 use crate::name_of_thy_func;
1688
1689 #[derive(PartialEq, Eq, PartialOrd, Ord)]
1690 enum Precedence {
1691 Iff,
1692 Imp,
1693 Or,
1694 And,
1695 Cmp,
1696 Bitvec,
1697 AddSub,
1698 MulDiv,
1699 }
1700
1701 impl BinOp {
1702 fn precedence(&self) -> Precedence {
1703 match self {
1704 BinOp::Iff => Precedence::Iff,
1705 BinOp::Imp => Precedence::Imp,
1706 BinOp::Or => Precedence::Or,
1707 BinOp::And => Precedence::And,
1708 BinOp::Eq
1709 | BinOp::Ne
1710 | BinOp::Gt(_)
1711 | BinOp::Lt(_)
1712 | BinOp::Ge(_)
1713 | BinOp::Le(_) => Precedence::Cmp,
1714 BinOp::Add(_) | BinOp::Sub(_) => Precedence::AddSub,
1715 BinOp::Mul(_) | BinOp::Div(_) | BinOp::Mod(_) => Precedence::MulDiv,
1716 BinOp::BitAnd(_)
1717 | BinOp::BitOr(_)
1718 | BinOp::BitShl(_)
1719 | BinOp::BitShr(_)
1720 | BinOp::BitXor(_) => Precedence::Bitvec,
1721 }
1722 }
1723 }
1724
1725 impl Precedence {
1726 pub fn is_associative(&self) -> bool {
1727 !matches!(self, Precedence::Imp | Precedence::Cmp)
1728 }
1729 }
1730
1731 pub fn should_parenthesize(op: &BinOp, child: &Expr) -> bool {
1732 if let ExprKind::BinaryOp(child_op, ..) = child.kind() {
1733 child_op.precedence() < op.precedence()
1734 || (child_op.precedence() == op.precedence() && !op.precedence().is_associative())
1735 } else {
1736 false
1737 }
1738 }
1739
1740 impl Pretty for Ctor {
1741 fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1742 match self {
1743 Ctor::Struct(def_id) => {
1744 w!(cx, f, "{:?}", def_id)
1745 }
1746 Ctor::Enum(def_id, variant_idx) => {
1747 w!(cx, f, "{:?}::{:?}", def_id, ^variant_idx)
1748 }
1749 Ctor::RawPtr => w!(cx, f, "ptr"),
1750 }
1751 }
1752 }
1753
1754 impl Pretty for fhir::QuantKind {
1755 fn fmt(&self, _cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1756 match self {
1757 fhir::QuantKind::Exists => w!(cx, f, "∃"),
1758 fhir::QuantKind::Forall => w!(cx, f, "∀"),
1759 }
1760 }
1761 }
1762
1763 impl Pretty for InternalFuncKind {
1764 fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1765 match self {
1766 InternalFuncKind::Val(op) => w!(cx, f, "[{:?}]", op),
1767 InternalFuncKind::Rel(op) => w!(cx, f, "[{:?}]?", op),
1768 InternalFuncKind::Cast => w!(cx, f, "cast"),
1769 }
1770 }
1771 }
1772
1773 impl Pretty for QuantDom {
1774 fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1775 match self {
1776 QuantDom::Bounded { start, end } => w!(cx, f, "in {} .. {}", ^start, ^end),
1777 QuantDom::Unbounded => Ok(()),
1778 }
1779 }
1780 }
1781
1782 impl Pretty for Expr {
1783 fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1784 let e = if cx.simplify_exprs {
1785 self.simplify(&SnapshotMap::default())
1786 } else {
1787 self.clone()
1788 };
1789 match e.kind() {
1790 ExprKind::Var(var) => w!(cx, f, "{:?}", var),
1791 ExprKind::Local(local) => w!(cx, f, "{:?}", ^local),
1792 ExprKind::ConstDefId(did) => w!(cx, f, "{}", ^def_id_to_string(*did)),
1793 ExprKind::Constant(c) => w!(cx, f, "{:?}", c),
1794
1795 ExprKind::BinaryOp(op, e1, e2) => {
1796 if should_parenthesize(op, e1) {
1797 w!(cx, f, "({:?})", e1)?;
1798 } else {
1799 w!(cx, f, "{:?}", e1)?;
1800 }
1801 if matches!(op, BinOp::Div(_)) {
1802 w!(cx, f, "{:?}", op)?;
1803 } else {
1804 w!(cx, f, " {:?} ", op)?;
1805 }
1806 if should_parenthesize(op, e2) {
1807 w!(cx, f, "({:?})", e2)?;
1808 } else {
1809 w!(cx, f, "{:?}", e2)?;
1810 }
1811 Ok(())
1812 }
1813 ExprKind::UnaryOp(op, e) => {
1814 if e.is_atom() {
1815 w!(cx, f, "{:?}{:?}", op, e)
1816 } else {
1817 w!(cx, f, "{:?}({:?})", op, e)
1818 }
1819 }
1820 ExprKind::FieldProj(e, proj) if let ExprKind::Ctor(_, _) = e.kind() => {
1821 w!(cx, f, "{:?}", e.proj_and_reduce(*proj))
1824 }
1825 ExprKind::FieldProj(e, proj) => {
1826 if e.is_atom() {
1827 w!(cx, f, "{:?}.{}", e, ^fmt_field_proj(cx, *proj))
1828 } else {
1829 w!(cx, f, "({:?}).{}", e, ^fmt_field_proj(cx, *proj))
1830 }
1831 }
1832 ExprKind::Tuple(flds) => {
1833 if let [e] = &flds[..] {
1834 w!(cx, f, "({:?},)", e)
1835 } else {
1836 w!(cx, f, "({:?})", join!(", ", flds))
1837 }
1838 }
1839 ExprKind::IsCtor(def_id, variant_idx, idx) => {
1840 w!(cx, f, "({:?} is {:?}::{:?})", idx, def_id, ^variant_idx)
1841 }
1842 ExprKind::Ctor(ctor, flds) => {
1843 if matches!(ctor, Ctor::RawPtr) {
1844 let fields = iter::zip(RawPtrField::iter(), flds)
1845 .map(|(field, value)| {
1846 FieldBind { name: field.symbol(), value: value.clone() }
1847 })
1848 .collect_vec();
1849 return w!(cx, f, "ptr {{ {:?} }}", join!(", ", fields));
1850 }
1851 let Some((def_id, variant_idx)) = ctor.def_id_and_variant() else {
1852 unreachable!()
1853 };
1854 if let Some(adt_sort_def) = cx.adt_sort_def_of(def_id) {
1855 let variant = adt_sort_def.variant(variant_idx).field_names();
1856 let fields = iter::zip(variant, flds)
1857 .map(|(name, value)| FieldBind { name: *name, value: value.clone() })
1858 .collect_vec();
1859 match ctor {
1860 Ctor::Struct(_) => {
1861 w!(cx, f, "{:?} {{ {:?} }}", def_id, join!(", ", fields))
1862 }
1863 Ctor::Enum(_, idx) => {
1864 if fields.is_empty() {
1865 w!(cx, f, "{:?}::{:?}", def_id, ^idx.index())
1866 } else {
1867 w!(cx, f, "{:?}::{:?}({:?})", def_id, ^idx.index(), join!(", ", fields))
1868 }
1869 }
1870 Ctor::RawPtr => unreachable!(),
1871 }
1872 } else {
1873 match ctor {
1874 Ctor::Struct(_) => {
1875 w!(cx, f, "{:?} {{ {:?} }}", def_id, join!(", ", flds))
1876 }
1877 Ctor::Enum(_, idx) => {
1878 w!(cx, f, "{:?}::{:?} {{ {:?} }}", def_id, ^idx, join!(", ", flds))
1879 }
1880 Ctor::RawPtr => unreachable!(),
1881 }
1882 }
1883 }
1884 ExprKind::PathProj(e, field) => {
1885 if e.is_atom() {
1886 w!(cx, f, "{:?}.{:?}", e, field)
1887 } else {
1888 w!(cx, f, "({:?}).{:?}", e, field)
1889 }
1890 }
1891 ExprKind::App(func, _, args) => {
1892 w!(cx, f, "{:?}({})",
1893 parens!(func, !func.is_atom()),
1894 ^args
1895 .iter()
1896 .format_with(", ", |arg, f| f(&format_args_cx!(cx, "{:?}", arg)))
1897 )
1898 }
1899 ExprKind::IfThenElse(p, e1, e2) => {
1900 w!(cx, f, "if {:?} {{ {:?} }} else {{ {:?} }}", p, e1, e2)
1901 }
1902 ExprKind::Hole(_) => {
1903 w!(cx, f, "*")
1904 }
1905 ExprKind::KVar(kvar) => {
1906 w!(cx, f, "{:?}", kvar)
1907 }
1908 ExprKind::WKVar(wkvar) => {
1909 w!(cx, f, "{:?}", wkvar)
1910 }
1911 ExprKind::Alias(alias, args) => {
1912 w!(cx, f, "{:?}({:?})", alias, join!(", ", args))
1913 }
1914 ExprKind::Abs(lam) => {
1915 w!(cx, f, "{:?}", lam)
1916 }
1917 ExprKind::GlobalFunc(SpecFuncKind::Def(did)) => {
1918 w!(cx, f, "{}", ^did.name())
1919 }
1920 ExprKind::GlobalFunc(SpecFuncKind::Thy(itf)) => {
1921 if let Some(name) = name_of_thy_func(*itf) {
1922 w!(cx, f, "{}", ^name)
1923 } else {
1924 w!(cx, f, "<error>")
1925 }
1926 }
1927 ExprKind::InternalFunc(func) => {
1928 w!(cx, f, "{:?}", func)
1929 }
1930 ExprKind::Quant(kind, dom, body) => {
1931 let vars = body.vars();
1932 cx.with_bound_vars(vars, || {
1933 w!(cx, f, "{:?} {:?} {{ {:?} }}", kind, dom, body.skip_binder_ref())
1934 })
1935 }
1936 ExprKind::Let(init, body) => {
1937 let vars = body.vars();
1938 cx.with_bound_vars(vars, || {
1939 cx.fmt_bound_vars(false, "(let ", vars, " = ", f)?;
1940 w!(cx, f, "{:?} in {:?})", init, body.skip_binder_ref())
1941 })
1942 }
1943 }
1944 }
1945 }
1946
1947 fn fmt_field_proj(cx: &PrettyCx, proj: FieldProj) -> String {
1948 if let FieldProj::Adt { def_id, field } = proj
1949 && let Some(adt_sort_def) = cx.adt_sort_def_of(def_id)
1950 {
1951 format!("{}", adt_sort_def.struct_variant().field_names()[field as usize])
1952 } else if let FieldProj::RawPtr { field } = proj {
1953 field.name().to_string()
1954 } else {
1955 format!("{}", proj.field_idx())
1956 }
1957 }
1958
1959 impl Pretty for Constant {
1960 fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1961 match self {
1962 Constant::Int(i) => w!(cx, f, "{i}"),
1963 Constant::BitVec(i, sz) => w!(cx, f, "bv({i}, {sz})"),
1964 Constant::Real(r) => w!(cx, f, "{}", ^r.0),
1965 Constant::Bool(b) => w!(cx, f, "{b}"),
1966 Constant::Str(sym) => w!(cx, f, "\"{sym}\""),
1967 Constant::Char(c) => w!(cx, f, "\'{c}\'"),
1968 }
1969 }
1970 }
1971
1972 impl Pretty for AliasReft {
1973 fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1974 w!(cx, f, "<({:?}) as {:?}", &self.args[0], self.assoc_id.parent())?;
1975 let args = &self.args[1..];
1976 if !args.is_empty() {
1977 w!(cx, f, "<{:?}>", join!(", ", args))?;
1978 }
1979 w!(cx, f, ">::{}", ^self.assoc_id.name())
1980 }
1981 }
1982
1983 impl Pretty for Lambda {
1984 fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1985 let vars = self.body.vars();
1986 cx.with_bound_vars(vars, || {
1989 cx.fmt_bound_vars(false, "λ", vars, ". ", f)?;
1990 w!(cx, f, "{:?}", self.body.as_ref().skip_binder())
1991 })
1992 }
1993 }
1994
1995 impl Pretty for Var {
1996 fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1997 match self {
1998 Var::Bound(debruijn, var) => cx.fmt_bound_reft(*debruijn, *var, f),
1999 Var::EarlyParam(var) => w!(cx, f, "{}", ^var.name),
2000 Var::Free(name) => w!(cx, f, "{:?}", ^name),
2001 Var::EVar(evar) => w!(cx, f, "{:?}", ^evar),
2002 Var::ConstGeneric(param) => w!(cx, f, "{}", ^param.name),
2003 }
2004 }
2005 }
2006
2007 impl Pretty for KVar {
2008 fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2009 w!(cx, f, "{:?}", ^self.kvid)?;
2010 match cx.kvar_args {
2011 KVarArgs::All => {
2012 w!(
2013 cx,
2014 f,
2015 "({:?})[{:?}]",
2016 join!(", ", self.self_args()),
2017 join!(", ", self.scope())
2018 )?;
2019 }
2020 KVarArgs::SelfOnly => w!(cx, f, "({:?})", join!(", ", self.self_args()))?,
2021 KVarArgs::Hide => {}
2022 }
2023 Ok(())
2024 }
2025 }
2026
2027 impl Pretty for WKVar {
2028 fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2029 w!(cx, f, "$wk{}_{}", ^self.wkvid.id.index(), ^cx.tcx().def_path_str(self.wkvid.parent_fn))?;
2032 w!(cx, f, "({:?})[{:?}]", join!(", ", self.self_args()), join!(", ", self.scope()))?;
2033 Ok(())
2034 }
2035 }
2036
2037 impl Pretty for Path {
2038 fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2039 w!(cx, f, "{:?}", &self.loc)?;
2040 for field in &self.projection {
2041 w!(cx, f, ".{}", ^u32::from(*field))?;
2042 }
2043 Ok(())
2044 }
2045 }
2046
2047 impl Pretty for Loc {
2048 fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2049 match self {
2050 Loc::Local(local) => w!(cx, f, "{:?}", ^local),
2051 Loc::Var(var) => w!(cx, f, "{:?}", var),
2052 }
2053 }
2054 }
2055
2056 impl Pretty for BinOp {
2057 fn fmt(&self, _cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2058 match self {
2059 BinOp::Iff => w!(cx, f, "<=>"),
2060 BinOp::Imp => w!(cx, f, "=>"),
2061 BinOp::Or => w!(cx, f, "||"),
2062 BinOp::And => w!(cx, f, "&&"),
2063 BinOp::Eq => w!(cx, f, "=="),
2064 BinOp::Ne => w!(cx, f, "!="),
2065 BinOp::Gt(_) => w!(cx, f, ">"),
2066 BinOp::Ge(_) => w!(cx, f, ">="),
2067 BinOp::Lt(_) => w!(cx, f, "<"),
2068 BinOp::Le(_) => w!(cx, f, "<="),
2069 BinOp::Add(_) => w!(cx, f, "+"),
2070 BinOp::Sub(_) => w!(cx, f, "-"),
2071 BinOp::Mul(_) => w!(cx, f, "*"),
2072 BinOp::Div(_) => w!(cx, f, "/"),
2073 BinOp::Mod(_) => w!(cx, f, "mod"),
2074 BinOp::BitAnd(_) => w!(cx, f, "&"),
2075 BinOp::BitOr(_) => w!(cx, f, "|"),
2076 BinOp::BitXor(_) => w!(cx, f, "^"),
2077 BinOp::BitShl(_) => w!(cx, f, "<<"),
2078 BinOp::BitShr(_) => w!(cx, f, ">>"),
2079 }
2080 }
2081 }
2082
2083 impl Pretty for UnOp {
2084 fn fmt(&self, _cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2085 match self {
2086 UnOp::Not => w!(cx, f, "!"),
2087 UnOp::Neg => w!(cx, f, "-"),
2088 }
2089 }
2090 }
2091
2092 impl_debug_with_default_cx!(Expr, Loc, Path, Var, KVar, WKVar, Lambda, AliasReft);
2093
2094 impl PrettyNested for Lambda {
2095 fn fmt_nested(&self, cx: &PrettyCx) -> Result<NestedString, fmt::Error> {
2096 cx.nested_with_bound_vars("λ", self.body.vars(), None, |prefix| {
2098 let expr_d = self.body.skip_binder_ref().fmt_nested(cx)?;
2099 let text = format!("{}{}", prefix, expr_d.text);
2100 Ok(NestedString { text, children: expr_d.children, key: None })
2101 })
2102 }
2103 }
2104
2105 pub fn aggregate_nested(
2106 cx: &PrettyCx,
2107 ctor: &Ctor,
2108 flds: &[Expr],
2109 is_named: bool,
2110 ) -> Result<NestedString, fmt::Error> {
2111 let mut text =
2112 if is_named && ctor.is_enum() { format_cx!(cx, "{:?}", ctor) } else { "".to_string() };
2113 if flds.is_empty() {
2114 Ok(NestedString { text, children: None, key: None })
2116 } else if flds.len() == 1 {
2117 text += &flds[0].fmt_nested(cx)?.text;
2119 Ok(NestedString { text, children: None, key: None })
2120 } else {
2121 let keys = if let Some((def_id, variant_idx)) = ctor.def_id_and_variant()
2122 && let Some(adt_sort_def) = cx.adt_sort_def_of(def_id)
2123 {
2124 adt_sort_def
2125 .variant(variant_idx)
2126 .field_names()
2127 .iter()
2128 .map(|name| format!("{name}"))
2129 .collect_vec()
2130 } else if matches!(ctor, Ctor::RawPtr) {
2131 RawPtrField::iter()
2132 .map(|field| field.name().to_string())
2133 .collect_vec()
2134 } else {
2135 (0..flds.len()).map(|i| format!("arg{i}")).collect_vec()
2136 };
2137 text += "{..}";
2139 let mut children = vec![];
2140 for (key, fld) in iter::zip(keys, flds) {
2141 let fld_d = fld.fmt_nested(cx)?;
2142 children.push(NestedString { key: Some(key), ..fld_d });
2143 }
2144 Ok(NestedString { text, children: Some(children), key: None })
2145 }
2146 }
2147
2148 impl PrettyNested for Name {
2149 fn fmt_nested(&self, cx: &PrettyCx) -> Result<NestedString, fmt::Error> {
2150 let text = cx.pretty_var_env.get(&PrettyVar::Local(*self));
2151 Ok(NestedString { text, key: None, children: None })
2152 }
2153 }
2154
2155 impl PrettyNested for Expr {
2156 fn fmt_nested(&self, cx: &PrettyCx) -> Result<NestedString, fmt::Error> {
2157 let e = if cx.simplify_exprs {
2158 self.simplify(&SnapshotMap::default())
2159 } else {
2160 self.clone()
2161 };
2162 match e.kind() {
2163 ExprKind::Var(Var::Free(name)) => name.fmt_nested(cx),
2164 ExprKind::Var(..)
2165 | ExprKind::Local(..)
2166 | ExprKind::Constant(..)
2167 | ExprKind::ConstDefId(..)
2168 | ExprKind::Hole(..)
2169 | ExprKind::GlobalFunc(..)
2170 | ExprKind::InternalFunc(..) => debug_nested(cx, &e),
2171 ExprKind::WKVar(..) => debug_nested(cx, &e),
2172 ExprKind::KVar(kvar) => {
2173 let kv = format!("{:?}", kvar.kvid);
2174 let mut strs = vec![kv];
2175 for arg in &kvar.args {
2176 strs.push(arg.fmt_nested(cx)?.text);
2177 }
2178 let text = format!("##[{}]##", strs.join("##"));
2179 Ok(NestedString { text, children: None, key: None })
2180 }
2181 ExprKind::IfThenElse(p, e1, e2) => {
2182 let p_d = p.fmt_nested(cx)?;
2183 let e1_d = e1.fmt_nested(cx)?;
2184 let e2_d = e2.fmt_nested(cx)?;
2185 let text = format!("(if {} then {} else {})", p_d.text, e1_d.text, e2_d.text);
2186 let children = float_children(vec![p_d.children, e1_d.children, e2_d.children]);
2187 Ok(NestedString { text, children, key: None })
2188 }
2189 ExprKind::BinaryOp(op, e1, e2) => {
2190 let e1_d = e1.fmt_nested(cx)?;
2191 let e2_d = e2.fmt_nested(cx)?;
2192 let e1_text = if should_parenthesize(op, e1) {
2193 format!("({})", e1_d.text)
2194 } else {
2195 e1_d.text
2196 };
2197 let e2_text = if should_parenthesize(op, e2) {
2198 format!("({})", e2_d.text)
2199 } else {
2200 e2_d.text
2201 };
2202 let op_d = debug_nested(cx, op)?;
2203 let op_text = if matches!(op, BinOp::Div(_)) {
2204 op_d.text
2205 } else {
2206 format!(" {} ", op_d.text)
2207 };
2208 let text = format!("{e1_text}{op_text}{e2_text}");
2209 let children = float_children(vec![e1_d.children, e2_d.children]);
2210 Ok(NestedString { text, children, key: None })
2211 }
2212 ExprKind::UnaryOp(op, e) => {
2213 let e_d = e.fmt_nested(cx)?;
2214 let op_d = debug_nested(cx, op)?;
2215 let text = if e.is_atom() {
2216 format!("{}{}", op_d.text, e_d.text)
2217 } else {
2218 format!("{}({})", op_d.text, e_d.text)
2219 };
2220 Ok(NestedString { text, children: e_d.children, key: None })
2221 }
2222 ExprKind::FieldProj(e, proj) if let ExprKind::Ctor(_, _) = e.kind() => {
2223 e.proj_and_reduce(*proj).fmt_nested(cx)
2226 }
2227 ExprKind::FieldProj(e, proj) => {
2228 let e_d = e.fmt_nested(cx)?;
2229 let text = if e.is_atom() {
2230 format!("{}.{}", e_d.text, fmt_field_proj(cx, *proj))
2231 } else {
2232 format!("({}).{}", e_d.text, fmt_field_proj(cx, *proj))
2233 };
2234 Ok(NestedString { text, children: e_d.children, key: None })
2235 }
2236 ExprKind::Tuple(flds) => {
2237 let mut texts = vec![];
2238 let mut kidss = vec![];
2239 for e in flds {
2240 let e_d = e.fmt_nested(cx)?;
2241 texts.push(e_d.text);
2242 kidss.push(e_d.children);
2243 }
2244 let text = if let [e] = &texts[..] {
2245 format!("({e},)")
2246 } else {
2247 format!("({})", texts.join(", "))
2248 };
2249 let children = float_children(kidss);
2250 Ok(NestedString { text, children, key: None })
2251 }
2252 ExprKind::Ctor(ctor, flds) => aggregate_nested(cx, ctor, flds, true),
2253 ExprKind::IsCtor(def_id, variant_idx, idx) => {
2254 let text = format!("is::{:?}::{:?}( {:?} )", def_id, variant_idx, idx);
2255 Ok(NestedString { text, children: None, key: None })
2256 }
2257 ExprKind::PathProj(e, field) => {
2258 let e_d = e.fmt_nested(cx)?;
2259 let text = if e.is_atom() {
2260 format!("{}.{:?}", e_d.text, field)
2261 } else {
2262 format!("({}).{:?}", e_d.text, field)
2263 };
2264 Ok(NestedString { text, children: e_d.children, key: None })
2265 }
2266 ExprKind::Alias(alias, args) => {
2267 let mut texts = vec![];
2268 let mut kidss = vec![];
2269 for arg in args {
2270 let arg_d = arg.fmt_nested(cx)?;
2271 texts.push(arg_d.text);
2272 kidss.push(arg_d.children);
2273 }
2274 let text = format_cx!(cx, "{:?}({:?})", alias, texts.join(", "));
2275 let children = float_children(kidss);
2276 Ok(NestedString { text, children, key: None })
2277 }
2278 ExprKind::App(func, _, args) => {
2279 let func_d = func.fmt_nested(cx)?;
2280 let mut texts = vec![];
2281 let mut kidss = vec![func_d.children];
2282 for arg in args {
2283 let arg_d = arg.fmt_nested(cx)?;
2284 texts.push(arg_d.text);
2285 kidss.push(arg_d.children);
2286 }
2287 let text = if func.is_atom() {
2288 format!("{}({})", func_d.text, texts.join(", "))
2289 } else {
2290 format!("({})({})", func_d.text, texts.join(", "))
2291 };
2292 let children = float_children(kidss);
2293 Ok(NestedString { text, children, key: None })
2294 }
2295 ExprKind::Abs(lambda) => lambda.fmt_nested(cx),
2296 ExprKind::Let(init, body) => {
2297 cx.nested_with_bound_vars("let", body.vars(), None, |prefix| {
2299 let body = body.skip_binder_ref().fmt_nested(cx)?;
2300 let text = format!("{:?} {}{}", init, prefix, body.text);
2301 Ok(NestedString { text, children: body.children, key: None })
2302 })
2303 }
2304 ExprKind::Quant(kind, dom, body) => {
2305 let left = match kind {
2306 fhir::QuantKind::Forall => "∀",
2307 fhir::QuantKind::Exists => "∃",
2308 };
2309 let right = Some(format!(" {:?}", dom));
2310
2311 cx.nested_with_bound_vars(left, body.vars(), right, |all_str| {
2312 let expr_d = body.as_ref().skip_binder().fmt_nested(cx)?;
2313 let text = format!("{}{}", all_str, expr_d.text);
2314 Ok(NestedString { text, children: expr_d.children, key: None })
2315 })
2316 }
2317 }
2318 }
2319 }
2320}
2321
2322impl Expr {
2323 pub fn prettify(&self) -> Self {
2325 self.fold_constants()
2326 .push_negations()
2327 .simplify_arithmetic()
2328 .simplify_bounds()
2329 }
2330
2331 pub fn fold_constants(&self) -> Self {
2333 let span = self.span();
2334 match self.kind() {
2335 ExprKind::UnaryOp(op, a) => {
2336 let a_fold = a.fold_constants();
2337
2338 if let ExprKind::Constant(c) = a_fold.kind() {
2339 match (op, c) {
2340 (UnOp::Not, Constant::Bool(b)) => {
2341 return Expr::constant(Constant::Bool(!b)).at_opt(span);
2342 }
2343 (UnOp::Neg, Constant::Int(n)) => {
2344 return Expr::constant(Constant::Int(n.neg())).at_opt(span);
2345 }
2346 _ => {}
2347 }
2348 }
2349 Expr::unary_op(*op, a_fold).at_opt(span)
2350 }
2351
2352 ExprKind::BinaryOp(op, a, b) => {
2353 let a_fold = a.fold_constants();
2354 let b_fold = b.fold_constants();
2355
2356 if let (ExprKind::Constant(c1), ExprKind::Constant(c2)) =
2357 (a_fold.kind(), b_fold.kind())
2358 {
2359 if let Some(c3) = Expr::const_op(op, c1, c2) {
2361 return Expr::constant(c3).at_opt(span);
2362 }
2363
2364 if let (Constant::Int(n1), Constant::Int(n2)) = (c1, c2) {
2366 let result = match op {
2367 BinOp::Add(_) => n1.checked_add(n2),
2368 BinOp::Sub(_) => n1.checked_sub(n2),
2369 BinOp::Mul(_) => n1.checked_mul(n2),
2370 BinOp::Div(_) => n1.checked_div(n2),
2371 BinOp::Mod(_) => n1.checked_rem(n2),
2372 _ => None,
2373 };
2374
2375 if let Some(res) = result {
2376 return Expr::constant(Constant::Int(res)).at_opt(span);
2377 }
2378 }
2379 }
2380
2381 Expr::binary_op(op.clone(), a_fold, b_fold).at_opt(span)
2382 }
2383
2384 ExprKind::IfThenElse(p, e1, e2) => {
2385 let p_fold = p.fold_constants();
2386
2387 if let ExprKind::Constant(Constant::Bool(b)) = p_fold.kind() {
2389 if *b {
2390 return e1.fold_constants().at_opt(span);
2391 } else {
2392 return e2.fold_constants().at_opt(span);
2393 }
2394 }
2395
2396 Expr::ite(p_fold, e1.fold_constants(), e2.fold_constants()).at_opt(span)
2397 }
2398
2399 _ => self.clone(),
2402 }
2403 }
2404
2405 pub fn push_negations(&self) -> Self {
2407 let span = self.span();
2408 match self.kind() {
2409 ExprKind::UnaryOp(UnOp::Not, inner) => {
2410 match inner.kind() {
2411 ExprKind::UnaryOp(UnOp::Not, a) => a.push_negations().at_opt(span),
2413
2414 ExprKind::BinaryOp(BinOp::Le(s), a, b) => {
2416 Expr::binary_op(
2417 BinOp::Gt(s.clone()),
2418 a.push_negations(),
2419 b.push_negations(),
2420 )
2421 .at_opt(span)
2422 }
2423 ExprKind::BinaryOp(BinOp::Lt(s), a, b) => {
2424 Expr::binary_op(
2425 BinOp::Ge(s.clone()),
2426 a.push_negations(),
2427 b.push_negations(),
2428 )
2429 .at_opt(span)
2430 }
2431 ExprKind::BinaryOp(BinOp::Ge(s), a, b) => {
2432 Expr::binary_op(
2433 BinOp::Lt(s.clone()),
2434 a.push_negations(),
2435 b.push_negations(),
2436 )
2437 .at_opt(span)
2438 }
2439 ExprKind::BinaryOp(BinOp::Gt(s), a, b) => {
2440 Expr::binary_op(
2441 BinOp::Le(s.clone()),
2442 a.push_negations(),
2443 b.push_negations(),
2444 )
2445 .at_opt(span)
2446 }
2447
2448 ExprKind::BinaryOp(BinOp::Eq, a, b) => {
2450 Expr::binary_op(BinOp::Ne, a.push_negations(), b.push_negations())
2451 .at_opt(span)
2452 }
2453 ExprKind::BinaryOp(BinOp::Ne, a, b) => {
2454 Expr::binary_op(BinOp::Eq, a.push_negations(), b.push_negations())
2455 .at_opt(span)
2456 }
2457
2458 ExprKind::BinaryOp(BinOp::Or, a, b) => {
2460 Expr::binary_op(
2461 BinOp::And,
2462 a.not().push_negations(),
2463 b.not().push_negations(),
2464 )
2465 .at_opt(span)
2466 }
2467 ExprKind::BinaryOp(BinOp::And, a, b) => {
2468 Expr::binary_op(
2469 BinOp::Or,
2470 a.not().push_negations(),
2471 b.not().push_negations(),
2472 )
2473 .at_opt(span)
2474 }
2475
2476 _ => Expr::unary_op(UnOp::Not, inner.push_negations()).at_opt(span),
2478 }
2479 }
2480 ExprKind::BinaryOp(op, a, b) => {
2481 Expr::binary_op(op.clone(), a.push_negations(), b.push_negations()).at_opt(span)
2482 }
2483 ExprKind::UnaryOp(op, a) => Expr::unary_op(*op, a.push_negations()).at_opt(span),
2484 ExprKind::IfThenElse(p, e1, e2) => {
2485 Expr::ite(p.push_negations(), e1.push_negations(), e2.push_negations()).at_opt(span)
2486 }
2487 _ => self.clone(),
2488 }
2489 }
2490
2491 pub fn simplify_arithmetic(&self) -> Self {
2493 let span = self.span();
2494 match self.kind() {
2495 ExprKind::BinaryOp(BinOp::Mul(s), a, b) => {
2496 let a_simp = a.simplify_arithmetic();
2497 let b_simp = b.simplify_arithmetic();
2498
2499 let is_minus_one = |e: &Expr| matches!(e.kind(), ExprKind::Constant(c) if *c == Constant::from(-1));
2500
2501 if is_minus_one(&b_simp) {
2502 return a_simp.neg().at_opt(span);
2503 }
2504 if is_minus_one(&a_simp) {
2505 return b_simp.neg().at_opt(span);
2506 }
2507
2508 Expr::binary_op(BinOp::Mul(s.clone()), a_simp, b_simp).at_opt(span)
2509 }
2510 ExprKind::BinaryOp(BinOp::Add(s), a, b) => {
2511 let a_simp = a.simplify_arithmetic();
2512 let b_simp = b.simplify_arithmetic();
2513
2514 if let ExprKind::UnaryOp(UnOp::Neg, x) = a_simp.kind() {
2515 return Expr::binary_op(BinOp::Sub(s.clone()), b_simp, x.clone()).at_opt(span);
2516 }
2517 if let ExprKind::UnaryOp(UnOp::Neg, y) = b_simp.kind() {
2518 return Expr::binary_op(BinOp::Sub(s.clone()), a_simp, y.clone()).at_opt(span);
2519 }
2520
2521 Expr::binary_op(BinOp::Add(s.clone()), a_simp, b_simp).at_opt(span)
2522 }
2523 ExprKind::BinaryOp(op, a, b) => {
2524 Expr::binary_op(op.clone(), a.simplify_arithmetic(), b.simplify_arithmetic())
2525 .at_opt(span)
2526 }
2527 ExprKind::UnaryOp(op, a) => Expr::unary_op(*op, a.simplify_arithmetic()).at_opt(span),
2528 ExprKind::IfThenElse(p, e1, e2) => {
2529 Expr::ite(
2530 p.simplify_arithmetic(),
2531 e1.simplify_arithmetic(),
2532 e2.simplify_arithmetic(),
2533 )
2534 .at_opt(span)
2535 }
2536 _ => self.clone(),
2537 }
2538 }
2539
2540 pub fn simplify_bounds(&self) -> Self {
2542 let span = self.span();
2543 match self.kind() {
2544 ExprKind::BinaryOp(op, a, b) => {
2545 let a_simp = a.simplify_bounds();
2546 let b_simp = b.simplify_bounds();
2547
2548 let is_minus_one = |e: &Expr| matches!(e.kind(), ExprKind::Constant(c) if *c == Constant::from(-1));
2549 let is_zero =
2550 |e: &Expr| matches!(e.kind(), ExprKind::Constant(c) if *c == Constant::from(0));
2551
2552 match op {
2554 BinOp::Gt(Sort::Int) => {
2555 if is_minus_one(&b_simp) {
2557 return Expr::binary_op(BinOp::Ge(Sort::Int), a_simp, Expr::zero())
2558 .at_opt(span)
2559 .simplify_bounds();
2560 }
2561 if is_zero(&b_simp)
2563 && let ExprKind::BinaryOp(BinOp::Sub(s_sub), x, y) = a_simp.kind()
2564 {
2565 return Expr::binary_op(BinOp::Gt(s_sub.clone()), x.clone(), y.clone())
2566 .at_opt(span);
2567 }
2568 }
2569 BinOp::Ge(Sort::Int) => {
2570 if is_zero(&b_simp)
2572 && let ExprKind::BinaryOp(BinOp::Sub(s_sub), x, y) = a_simp.kind()
2573 {
2574 return Expr::binary_op(BinOp::Ge(s_sub.clone()), x.clone(), y.clone())
2575 .at_opt(span);
2576 }
2577 }
2578 BinOp::Lt(Sort::Int) => {
2579 if is_zero(&b_simp)
2581 && let ExprKind::BinaryOp(BinOp::Sub(s_sub), x, y) = a_simp.kind()
2582 {
2583 return Expr::binary_op(BinOp::Lt(s_sub.clone()), x.clone(), y.clone())
2584 .at_opt(span);
2585 }
2586 }
2587 BinOp::Le(Sort::Int) => {
2588 if is_minus_one(&b_simp) {
2590 return Expr::binary_op(BinOp::Lt(Sort::Int), a_simp, Expr::zero())
2591 .at_opt(span)
2592 .simplify_bounds();
2593 }
2594 if is_zero(&b_simp)
2596 && let ExprKind::BinaryOp(BinOp::Sub(s_sub), x, y) = a_simp.kind()
2597 {
2598 return Expr::binary_op(BinOp::Le(s_sub.clone()), x.clone(), y.clone())
2599 .at_opt(span);
2600 }
2601 }
2602 _ => {}
2603 }
2604
2605 Expr::binary_op(op.clone(), a_simp, b_simp).at_opt(span)
2606 }
2607 ExprKind::UnaryOp(op, a) => Expr::unary_op(*op, a.simplify_bounds()).at_opt(span),
2608 ExprKind::IfThenElse(p, e1, e2) => {
2609 Expr::ite(p.simplify_bounds(), e1.simplify_bounds(), e2.simplify_bounds())
2610 .at_opt(span)
2611 }
2612 _ => self.clone(),
2613 }
2614 }
2615}