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_rel(op: BinOp, e1: impl Into<Expr>, e2: impl Into<Expr>) -> Expr {
357 Expr::app(InternalFuncKind::Rel(op), List::empty(), List::from_arr([e1.into(), e2.into()]))
358 }
359
360 pub fn unit_struct(def_id: DefId) -> Expr {
361 Expr::ctor_struct(def_id, List::empty())
362 }
363
364 pub fn cast(from: Sort, to: Sort, idx: Expr) -> Expr {
365 Expr::app(
366 InternalFuncKind::Cast,
367 List::from_arr([SortArg::Sort(from), SortArg::Sort(to)]),
368 List::from_arr([idx]),
369 )
370 }
371
372 pub fn app(func: impl Into<Expr>, sort_args: List<SortArg>, args: List<Expr>) -> Expr {
373 ExprKind::App(func.into(), sort_args, args).intern()
374 }
375
376 pub fn global_func(kind: SpecFuncKind) -> Expr {
377 ExprKind::GlobalFunc(kind).intern()
378 }
379
380 pub fn internal_func(kind: InternalFuncKind) -> Expr {
381 ExprKind::InternalFunc(kind).intern()
382 }
383
384 pub fn eq(e1: impl Into<Expr>, e2: impl Into<Expr>) -> Expr {
385 ExprKind::BinaryOp(BinOp::Eq, e1.into(), e2.into()).intern()
386 }
387
388 pub fn unary_op(op: UnOp, e: impl Into<Expr>) -> Expr {
389 ExprKind::UnaryOp(op, e.into()).intern()
390 }
391
392 pub fn ne(e1: impl Into<Expr>, e2: impl Into<Expr>) -> Expr {
393 ExprKind::BinaryOp(BinOp::Ne, e1.into(), e2.into()).intern()
394 }
395
396 pub fn ge(e1: impl Into<Expr>, e2: impl Into<Expr>) -> Expr {
397 ExprKind::BinaryOp(BinOp::Ge(Sort::Int), e1.into(), e2.into()).intern()
398 }
399
400 pub fn gt(e1: impl Into<Expr>, e2: impl Into<Expr>) -> Expr {
401 ExprKind::BinaryOp(BinOp::Gt(Sort::Int), e1.into(), e2.into()).intern()
402 }
403
404 pub fn lt(e1: impl Into<Expr>, e2: impl Into<Expr>) -> Expr {
405 ExprKind::BinaryOp(BinOp::Lt(Sort::Int), e1.into(), e2.into()).intern()
406 }
407
408 pub fn le(e1: impl Into<Expr>, e2: impl Into<Expr>) -> Expr {
409 ExprKind::BinaryOp(BinOp::Le(Sort::Int), e1.into(), e2.into()).intern()
410 }
411
412 pub fn implies(e1: impl Into<Expr>, e2: impl Into<Expr>) -> Expr {
413 ExprKind::BinaryOp(BinOp::Imp, e1.into(), e2.into()).intern()
414 }
415
416 pub fn field_proj(e: impl Into<Expr>, proj: FieldProj) -> Expr {
417 ExprKind::FieldProj(e.into(), proj).intern()
418 }
419
420 pub fn field_projs(e: impl Into<Expr>, projs: &[FieldProj]) -> Expr {
421 projs.iter().copied().fold(e.into(), Expr::field_proj)
422 }
423
424 pub fn path_proj(base: Expr, field: FieldIdx) -> Expr {
425 ExprKind::PathProj(base, field).intern()
426 }
427
428 pub fn not(&self) -> Expr {
429 ExprKind::UnaryOp(UnOp::Not, self.clone()).intern()
430 }
431
432 pub fn neg(&self) -> Expr {
433 ExprKind::UnaryOp(UnOp::Neg, self.clone()).intern()
434 }
435
436 pub fn kind(&self) -> &ExprKind {
437 &self.kind
438 }
439
440 pub fn is_atom(&self) -> bool {
443 !matches!(self.kind(), ExprKind::Abs(..) | ExprKind::BinaryOp(..) | ExprKind::Quant(..))
444 }
445
446 pub fn is_trivially_true(&self) -> bool {
449 self.is_true()
450 || matches!(self.kind(), ExprKind::BinaryOp(BinOp::Eq | BinOp::Iff | BinOp::Imp, e1, e2) if e1.erase_spans() == e2.erase_spans())
451 }
452
453 pub fn is_trivially_false(&self) -> bool {
455 self.is_false()
456 }
457
458 fn is_true(&self) -> bool {
460 matches!(self.kind(), ExprKind::Constant(Constant::Bool(true)))
461 }
462
463 fn is_false(&self) -> bool {
465 matches!(self.kind(), ExprKind::Constant(Constant::Bool(false)))
466 }
467
468 pub fn from_const(tcx: TyCtxt, c: &Const) -> Expr {
469 match &c.kind {
470 ConstKind::Param(param_const) => Expr::const_generic(*param_const),
471 ConstKind::Value(ty, ValTree::Leaf(scalar)) => {
472 Expr::constant(Constant::from_scalar_int(tcx, *scalar, ty).unwrap())
473 }
474 ConstKind::Value(_ty, ValTree::Branch(_)) => {
475 bug!("todo: ValTree::Branch {c:?}")
476 }
477 ConstKind::Alias(_) => bug!("unexpected `ConstKind::Alias`"),
479
480 ConstKind::Infer(_) => bug!("unexpected `ConstKind::Infer`"),
481 }
482 }
483
484 fn const_op(op: &BinOp, c1: &Constant, c2: &Constant) -> Option<Constant> {
485 match op {
486 BinOp::Iff => c1.iff(c2),
487 BinOp::Imp => c1.imp(c2),
488 BinOp::Or => c1.or(c2),
489 BinOp::And => c1.and(c2),
490 BinOp::Gt(Sort::Int) => c1.gt(c2),
491 BinOp::Ge(Sort::Int) => c1.ge(c2),
492 BinOp::Lt(Sort::Int) => c2.gt(c1),
493 BinOp::Le(Sort::Int) => c2.ge(c1),
494 BinOp::Eq => Some(c1.eq(c2)),
495 BinOp::Ne => Some(c1.ne(c2)),
496 _ => None,
497 }
498 }
499
500 pub fn simplify(&self, assumed_preds: &SnapshotMap<Expr, ()>) -> Expr {
506 struct Simplify<'a> {
507 assumed_preds: &'a SnapshotMap<Expr, ()>,
508 }
509
510 impl TypeFolder for Simplify<'_> {
511 fn fold_expr(&mut self, expr: &Expr) -> Expr {
512 if self.assumed_preds.get(&expr.erase_spans()).is_some() {
513 return Expr::tt();
514 }
515 let span = expr.span();
516 match expr.kind() {
517 ExprKind::BinaryOp(op, e1, e2) => {
518 let e1 = e1.fold_with(self);
519 let e2 = e2.fold_with(self);
520 match (op, e1.kind(), e2.kind()) {
521 (BinOp::And, ExprKind::Constant(Constant::Bool(false)), _) => {
522 Expr::constant(Constant::Bool(false)).at_opt(e1.span())
523 }
524 (BinOp::And, _, ExprKind::Constant(Constant::Bool(false))) => {
525 Expr::constant(Constant::Bool(false)).at_opt(e2.span())
526 }
527 (BinOp::And, ExprKind::Constant(Constant::Bool(true)), _) => e2,
528 (BinOp::And, _, ExprKind::Constant(Constant::Bool(true))) => e1,
529 (op, ExprKind::Constant(c1), ExprKind::Constant(c2)) => {
530 if let Some(c) = Expr::const_op(op, c1, c2) {
531 Expr::constant(c).at_opt(span.or(e2.span()))
532 } else {
533 Expr::binary_op(op.clone(), e1, e2).at_opt(span)
534 }
535 }
536 _ => Expr::binary_op(op.clone(), e1, e2).at_opt(span),
537 }
538 }
539 ExprKind::UnaryOp(UnOp::Not, e) => {
540 let e = e.fold_with(self);
541 match e.kind() {
542 ExprKind::Constant(Constant::Bool(b)) => {
543 Expr::constant(Constant::Bool(!b))
544 }
545 ExprKind::UnaryOp(UnOp::Not, e) => e.clone(),
546 ExprKind::BinaryOp(BinOp::Eq, e1, e2) => {
547 Expr::binary_op(BinOp::Ne, e1, e2).at_opt(span)
548 }
549 _ => Expr::unary_op(UnOp::Not, e).at_opt(span),
550 }
551 }
552 ExprKind::IfThenElse(p, e1, e2) => {
553 let p = p.fold_with(self);
554 if p.is_trivially_true() {
555 e1.fold_with(self).at_opt(span)
556 } else if p.is_trivially_false() {
557 e2.fold_with(self).at_opt(span)
558 } else {
559 Expr::ite(p, e1.fold_with(self), e2.fold_with(self)).at_opt(span)
560 }
561 }
562 _ => expr.super_fold_with(self),
563 }
564 }
565 }
566 self.fold_with(&mut Simplify { assumed_preds })
567 }
568
569 pub fn to_loc(&self) -> Option<Loc> {
570 match self.kind() {
571 ExprKind::Local(local) => Some(Loc::Local(*local)),
572 ExprKind::Var(var) => Some(Loc::Var(*var)),
573 _ => None,
574 }
575 }
576
577 pub fn to_path(&self) -> Option<Path> {
578 let mut expr = self;
579 let mut proj = vec![];
580 while let ExprKind::PathProj(e, field) = expr.kind() {
581 proj.push(*field);
582 expr = e;
583 }
584 proj.reverse();
585 Some(Path::new(expr.to_loc()?, proj))
586 }
587
588 pub fn is_unit(&self) -> bool {
590 matches!(self.kind(), ExprKind::Tuple(flds) if flds.is_empty())
591 || matches!(self.kind(), ExprKind::Ctor(Ctor::Struct(_), flds) if flds.is_empty())
592 }
593
594 pub fn eta_expand_abs(&self, inputs: &BoundVariableKinds, output: Sort) -> Lambda {
595 let args = (0..inputs.len())
596 .map(|idx| Expr::bvar(INNERMOST, BoundVar::from_usize(idx), BoundReftKind::Anon))
597 .collect();
598 let body = Expr::app(self, List::empty(), args);
599 Lambda::bind_with_vars(body, inputs.clone(), output)
600 }
601
602 pub fn proj_and_reduce(&self, proj: FieldProj) -> Expr {
604 match self.kind() {
605 ExprKind::Tuple(flds) | ExprKind::Ctor(Ctor::Struct(_) | Ctor::RawPtr, flds) => {
606 flds[proj.field_idx() as usize].clone()
607 }
608 _ => Expr::field_proj(self.clone(), proj),
609 }
610 }
611
612 pub fn reduce_ptr_addr(&self) -> Expr {
614 self.proj_and_reduce(FieldProj::RawPtr { field: RawPtrField::Addr })
615 }
616
617 pub fn visit_conj<'a>(&'a self, mut f: impl FnMut(&'a Expr)) {
618 fn go<'a>(e: &'a Expr, f: &mut impl FnMut(&'a Expr)) {
619 if let ExprKind::BinaryOp(BinOp::And, e1, e2) = e.kind() {
620 go(e1, f);
621 go(e2, f);
622 } else {
623 f(e);
624 }
625 }
626 go(self, &mut f);
627 }
628
629 pub fn flatten_conjs(&self) -> Vec<&Expr> {
630 let mut vec = vec![];
631 self.visit_conj(|e| vec.push(e));
632 vec
633 }
634
635 pub fn has_evars(&self) -> bool {
636 struct HasEvars;
637
638 impl TypeVisitor for HasEvars {
639 type BreakTy = ();
640 fn visit_expr(&mut self, expr: &Expr) -> ControlFlow<Self::BreakTy> {
641 if let ExprKind::Var(Var::EVar(_)) = expr.kind() {
642 ControlFlow::Break(())
643 } else {
644 expr.super_visit_with(self)
645 }
646 }
647 }
648
649 self.visit_with(&mut HasEvars).is_break()
650 }
651
652 pub fn erase_spans(&self) -> Expr {
653 struct SpanEraser;
654 impl TypeFolder for SpanEraser {
655 fn fold_expr(&mut self, e: &Expr) -> Expr {
656 e.super_fold_with(self).at_opt(None)
657 }
658 }
659 self.fold_with(&mut SpanEraser)
660 }
661
662 pub fn erase_bound_reft_kind(&self) -> Expr {
670 struct BoundReftKindEraser;
671 impl TypeFolder for BoundReftKindEraser {
672 fn fold_expr(&mut self, expr: &Expr) -> Expr {
673 if let ExprKind::Var(Var::Bound(
674 db_index,
675 BoundReft { var, kind: BoundReftKind::Named(_) },
676 )) = expr.kind()
677 {
678 Expr::bvar(*db_index, *var, BoundReftKind::Anon)
679 } else {
680 expr.super_fold_with(self)
681 }
682 }
683 }
684 self.fold_with(&mut BoundReftKindEraser)
685 }
686
687 pub fn erase_metadata(&self) -> Expr {
688 self.erase_spans().erase_bound_reft_kind()
689 }
690
691 pub fn expand_bin_rels(&self) -> Expr {
705 struct BinRelExpander;
706 impl BinRelExpander {
707 fn expand_bin_rel(&mut self, sort: &Sort, rel: &BinOp, e1: &Expr, e2: &Expr) -> Expr {
708 match sort {
709 Sort::Tuple(sorts) => {
710 let arity = sorts.len();
711 self.apply_bin_rel_rec(sorts, rel, e1, e2, |field| {
712 FieldProj::Tuple { arity, field }
713 })
714 }
715 Sort::App(SortCtor::Adt(sort_def), args)
716 if let Some(variant) = sort_def.opt_struct_variant() =>
717 {
718 let def_id = sort_def.did();
719 let sorts = variant.field_sorts(args);
720 self.apply_bin_rel_rec(&sorts, rel, e1, e2, |field| {
721 FieldProj::Adt { def_id, field }
722 })
723 }
724 _ => {
725 Expr::binary_op(
726 rel.clone(),
727 e1.super_fold_with(self),
728 e2.super_fold_with(self),
729 )
730 }
731 }
732 }
733 fn apply_bin_rel_rec(
735 &mut self,
736 sorts: &[Sort],
737 rel: &BinOp,
738 e1: &Expr,
739 e2: &Expr,
740 mk_proj: impl Fn(u32) -> FieldProj,
741 ) -> Expr {
742 Expr::and_from_iter(sorts.iter().enumerate().map(|(idx, s)| {
743 let proj = mk_proj(idx as u32);
744 let e1 = e1.proj_and_reduce(proj);
745 let e2 = e2.proj_and_reduce(proj);
746 self.expand_bin_rel(s, rel, &e1, &e2)
747 }))
748 }
749 }
750 impl TypeFolder for BinRelExpander {
751 fn fold_expr(&mut self, expr: &Expr) -> Expr {
752 if let ExprKind::BinaryOp(
753 rel @ (BinOp::Le(sort) | BinOp::Lt(sort) | BinOp::Ge(sort) | BinOp::Gt(sort)),
754 e1,
755 e2,
756 ) = expr.kind()
757 {
758 self.expand_bin_rel(sort, rel, e1, e2)
759 } else {
760 expr.super_fold_with(self)
761 }
762 }
763 }
764
765 let mut expander = BinRelExpander {};
766 self.fold_with(&mut expander)
767 }
768
769 pub fn eta_reduce_projs(&self) -> Self {
777 struct EtaReducer;
778 impl TypeFolder for EtaReducer {
779 fn fold_expr(&mut self, expr: &Expr) -> Expr {
780 match expr.kind() {
781 ExprKind::Tuple(subexprs) => {
782 let new_subexprs = subexprs
783 .iter()
784 .map(|subexpr| subexpr.fold_with(self))
785 .collect_vec();
786 if let Some(ExprKind::FieldProj(
787 e_inner,
788 FieldProj::Tuple { arity: _, field: 0 },
789 )) = subexprs.first().map(|e| e.kind())
790 && new_subexprs[1..].iter().zip(1..).all(|(other_e, i)| {
791 if let ExprKind::FieldProj(
792 other_e_inner,
793 FieldProj::Tuple { arity: _, field },
794 ) = other_e.kind()
795 {
796 field == &i && &e_inner.erase_metadata() == other_e_inner
797 } else {
798 false
799 }
800 })
801 {
802 e_inner.clone()
803 } else {
804 expr.clone()
805 }
806 }
807 ExprKind::Ctor(_ctor, subexprs) => {
808 let new_subexprs = subexprs
809 .iter()
810 .map(|subexpr| subexpr.fold_with(self))
811 .collect_vec();
812 if let Some(ExprKind::FieldProj(
813 e_inner,
814 FieldProj::Adt { def_id: _, field: 0 },
815 )) = subexprs.first().map(|e| e.kind())
816 && new_subexprs[1..].iter().zip(1..).all(|(other_e, i)| {
817 if let ExprKind::FieldProj(
818 other_e_inner,
819 FieldProj::Adt { def_id: _, field },
820 ) = other_e.kind()
821 {
822 field == &i && &e_inner.erase_metadata() == other_e_inner
823 } else {
824 false
825 }
826 })
827 {
828 e_inner.clone()
829 } else {
830 expr.clone()
831 }
832 }
833 _ => expr.super_fold_with(self),
834 }
835 }
836 }
837 self.fold_with(&mut EtaReducer)
838 }
839}
840
841#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Debug)]
842pub struct ESpan {
843 pub span: Span,
845 pub base: Option<Span>,
847}
848
849impl ESpan {
850 pub fn new(span: Span) -> Self {
851 Self { span, base: None }
852 }
853
854 pub fn with_base(&self, espan: ESpan) -> Self {
855 Self { span: self.span, base: Some(espan.span) }
856 }
857}
858
859#[derive(
860 Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Debug, TypeFoldable, TypeVisitable,
861)]
862pub enum BinOp {
863 Iff,
864 Imp,
865 Or,
866 And,
867 Eq,
868 Ne,
869 Gt(Sort),
870 Ge(Sort),
871 Lt(Sort),
872 Le(Sort),
873 Add(Sort),
874 Sub(Sort),
875 Mul(Sort),
876 Div(Sort),
877 Mod(Sort),
878 BitAnd(Sort),
879 BitOr(Sort),
880 BitXor(Sort),
881 BitShl(Sort),
882 BitShr(Sort),
883}
884
885impl BinOp {
886 pub fn is_uninterpreted(&self) -> bool {
890 matches!(
891 self,
892 BinOp::BitAnd(Sort::Int)
893 | BinOp::BitOr(Sort::Int)
894 | BinOp::BitXor(Sort::Int)
895 | BinOp::BitShl(Sort::Int)
896 | BinOp::BitShr(Sort::Int)
897 )
898 }
899
900 pub fn uif_sort(&self) -> Option<super::PolyFuncSort> {
906 let sort = match self {
907 BinOp::Add(sort)
908 | BinOp::Sub(sort)
909 | BinOp::Mul(sort)
910 | BinOp::Div(sort)
911 | BinOp::Mod(sort)
912 | BinOp::BitAnd(sort)
913 | BinOp::BitOr(sort)
914 | BinOp::BitXor(sort)
915 | BinOp::BitShl(sort)
916 | BinOp::BitShr(sort) => sort,
917 BinOp::Iff
918 | BinOp::Imp
919 | BinOp::Or
920 | BinOp::And
921 | BinOp::Eq
922 | BinOp::Ne
923 | BinOp::Gt(_)
924 | BinOp::Ge(_)
925 | BinOp::Lt(_)
926 | BinOp::Le(_) => return None,
927 };
928 let fsort = FuncSort::new(vec![sort.clone(), sort.clone()], sort.clone());
929 Some(super::PolyFuncSort::new(List::empty(), fsort))
930 }
931}
932
933#[derive(Clone, Copy, PartialEq, Eq, Hash, Encodable, Debug, Decodable)]
934pub enum UnOp {
935 Not,
936 Neg,
937}
938
939#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, TyEncodable, TyDecodable)]
940pub enum Ctor {
941 Struct(DefId),
943 Enum(DefId, VariantIdx),
945 RawPtr,
947}
948
949impl Ctor {
950 fn is_enum(&self) -> bool {
951 matches!(self, Self::Enum(..))
952 }
953
954 pub fn def_id_and_variant(&self) -> Option<(DefId, VariantIdx)> {
955 match self {
956 Self::Struct(def_id) => Some((*def_id, FIRST_VARIANT)),
957 Self::Enum(def_id, variant_idx) => Some((*def_id, *variant_idx)),
958 Self::RawPtr => None,
959 }
960 }
961}
962
963#[derive(Debug, Clone, TyEncodable, TyDecodable, PartialEq, Eq, Hash)]
977pub enum InternalFuncKind {
978 Rel(BinOp),
980 Cast,
982}
983
984#[derive(Debug, Clone, TyEncodable, TyDecodable, PartialEq, Eq, Hash)]
985pub enum SpecFuncKind {
986 Thy(liquid_fixpoint::ThyFunc),
988 Def(FluxDefId),
990}
991
992#[derive(
993 Clone, PartialEq, Eq, Hash, TyEncodable, Debug, TyDecodable, TypeVisitable, TypeFoldable,
994)]
995pub enum QuantDom {
996 Bounded { start: usize, end: usize },
997 Unbounded,
998}
999
1000#[derive(Clone, PartialEq, Eq, Hash, TyEncodable, Debug, TyDecodable)]
1001pub enum ExprKind {
1002 Var(Var),
1003 Local(Local),
1004 Constant(Constant),
1005 ConstDefId(DefId),
1007 BinaryOp(BinOp, Expr, Expr),
1008 GlobalFunc(SpecFuncKind),
1009 InternalFunc(InternalFuncKind),
1010 UnaryOp(UnOp, Expr),
1011 FieldProj(Expr, FieldProj),
1012 Ctor(Ctor, List<Expr>),
1014 Tuple(List<Expr>),
1015 PathProj(Expr, FieldIdx),
1016 IfThenElse(Expr, Expr, Expr),
1017 KVar(KVar),
1018 WKVar(WKVar),
1019 Alias(AliasReft, List<Expr>),
1020 Let(Expr, Binder<Expr>),
1021 App(Expr, List<SortArg>, List<Expr>),
1027 Abs(Lambda),
1037
1038 Quant(fhir::QuantKind, QuantDom, Binder<Expr>),
1040 Hole(HoleKind),
1054 IsCtor(DefId, VariantIdx, Expr),
1056}
1057
1058impl ExprKind {
1059 fn intern(self) -> Expr {
1060 Expr { kind: Interned::new(self), espan: None }
1061 }
1062}
1063
1064#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Debug)]
1065pub enum AggregateKind {
1066 Tuple(usize),
1067 Adt(DefId),
1068}
1069
1070#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Debug)]
1071pub enum FieldProj {
1072 Tuple { arity: usize, field: u32 },
1073 Adt { def_id: DefId, field: u32 },
1074 RawPtr { field: RawPtrField },
1075}
1076
1077#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Debug)]
1078pub enum RawPtrField {
1079 Base,
1080 Addr,
1081 Size,
1082}
1083
1084struct RawPtrFieldData {
1085 field: RawPtrField,
1086 index: u32,
1087 name: &'static str,
1088 sort: Sort,
1089}
1090
1091impl FieldProj {
1092 pub fn arity(&self, genv: GlobalEnv) -> QueryResult<usize> {
1093 match self {
1094 FieldProj::Tuple { arity, .. } => Ok(*arity),
1095 FieldProj::Adt { def_id, .. } => {
1096 Ok(genv.adt_sort_def_of(*def_id)?.struct_variant().fields())
1097 }
1098 FieldProj::RawPtr { .. } => Ok(RawPtrField::arity()),
1099 }
1100 }
1101
1102 pub fn field_idx(&self) -> u32 {
1103 match self {
1104 FieldProj::Tuple { field, .. } | FieldProj::Adt { field, .. } => *field,
1105 FieldProj::RawPtr { field } => field.index(),
1106 }
1107 }
1108}
1109
1110impl RawPtrField {
1111 const DATA: [RawPtrFieldData; 3] = [
1112 RawPtrFieldData { field: Self::Base, index: 0, name: "base", sort: Sort::Int },
1113 RawPtrFieldData { field: Self::Addr, index: 1, name: "addr", sort: Sort::Int },
1114 RawPtrFieldData { field: Self::Size, index: 2, name: "size", sort: Sort::Int },
1115 ];
1116
1117 pub fn iter() -> impl ExactSizeIterator<Item = Self> {
1118 Self::DATA.iter().map(|data| data.field)
1119 }
1120
1121 pub fn arity() -> usize {
1122 Self::DATA.len()
1123 }
1124
1125 fn data(self) -> &'static RawPtrFieldData {
1126 Self::DATA.iter().find(|data| data.field == self).unwrap()
1127 }
1128
1129 pub fn from_name(name: Symbol) -> Option<Self> {
1130 Self::DATA
1131 .iter()
1132 .find(|data| data.name == name.as_str())
1133 .map(|data| data.field)
1134 }
1135
1136 pub fn from_index(index: u32) -> Option<Self> {
1137 Self::DATA
1138 .iter()
1139 .find(|data| data.index == index)
1140 .map(|data| data.field)
1141 }
1142
1143 pub fn sort(self) -> Sort {
1144 self.data().sort.clone()
1145 }
1146
1147 pub fn index(self) -> u32 {
1148 self.data().index
1149 }
1150
1151 pub fn name(self) -> &'static str {
1152 self.data().name
1153 }
1154
1155 pub fn symbol(self) -> Symbol {
1156 match self {
1157 Self::Base => sym::base,
1158 Self::Addr => sym::addr,
1159 Self::Size => rustc_span::sym::size,
1160 }
1161 }
1162}
1163
1164#[derive(
1170 Debug, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, TypeFoldable, TypeVisitable,
1171)]
1172pub enum HoleKind {
1173 Pred,
1178 Expr(Sort),
1185}
1186
1187#[derive(Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, TypeVisitable, TypeFoldable)]
1193pub struct KVar {
1194 pub kvid: KVid,
1195 pub self_args: usize,
1197 pub args: List<Expr>,
1200}
1201
1202#[derive(
1203 Debug, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, TypeVisitable, TypeFoldable,
1204)]
1205pub struct WKVid {
1206 pub parent_fn: DefId,
1209 pub id: KVid,
1212}
1213
1214impl WKVid {
1215 pub fn new(parent_fn: DefId, id: KVid) -> Self {
1216 Self { parent_fn, id }
1217 }
1218}
1219
1220#[derive(Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, TypeVisitable, TypeFoldable)]
1225pub struct WKVar {
1226 pub wkvid: WKVid,
1227 pub self_args: usize,
1261 pub args: List<Expr>,
1263}
1264
1265#[derive(Clone, Debug, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Encodable, Decodable)]
1266pub struct EarlyReftParam {
1267 pub index: u32,
1268 pub name: Symbol,
1269}
1270
1271#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Encodable, Decodable, Debug)]
1272pub struct BoundReft {
1273 pub var: BoundVar,
1274 pub kind: BoundReftKind,
1275}
1276
1277#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, TyEncodable, TyDecodable)]
1278pub enum Var {
1279 Free(Name),
1280 Bound(DebruijnIndex, BoundReft),
1281 EarlyParam(EarlyReftParam),
1282 EVar(EVid),
1283 ConstGeneric(ParamConst),
1284}
1285
1286#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord, TyEncodable, TyDecodable)]
1287pub struct Path {
1288 pub loc: Loc,
1289 projection: List<FieldIdx>,
1290}
1291
1292#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, TyEncodable, TyDecodable)]
1293pub enum Loc {
1294 Local(Local),
1295 Var(Var),
1296}
1297
1298newtype_index! {
1299 #[debug_format = "?{}e"]
1301 #[orderable]
1302 #[encodable]
1303 pub struct EVid {}
1304}
1305
1306newtype_index! {
1307 #[debug_format = "$k{}"]
1308 #[encodable]
1309 pub struct KVid {}
1310}
1311
1312impl liquid_fixpoint::Identifier for KVid {
1313 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1314 write!(f, "k{}", self.as_u32())
1315 }
1316}
1317
1318newtype_index! {
1319 #[debug_format = "a{}"]
1320 #[orderable]
1321 #[encodable]
1322 pub struct Name {}
1323}
1324
1325#[derive(Copy, Debug, Clone)]
1326pub enum NameProvenance {
1327 Unknown,
1328 UnfoldBoundReft(BoundReftKind),
1329}
1330
1331impl NameProvenance {
1332 pub fn opt_symbol(&self) -> Option<Symbol> {
1333 match &self {
1334 NameProvenance::UnfoldBoundReft(BoundReftKind::Named(name)) => Some(*name),
1335 _ => None,
1336 }
1337 }
1338}
1339
1340#[derive(PartialEq, Eq, Hash, Debug)]
1341pub enum PrettyVar<V> {
1342 Local(V),
1343 Param(EarlyReftParam),
1344}
1345
1346impl<V: Copy + Into<usize>> PrettyVar<V> {
1347 pub fn as_subscript(&self) -> String {
1348 let idx = match self {
1349 PrettyVar::Local(v) => (*v).into(),
1350 PrettyVar::Param(p) => p.index as usize,
1351 };
1352 as_subscript(idx)
1353 }
1354}
1355
1356pub struct PrettyMap<V: Eq + Hash> {
1357 map: UnordMap<PrettyVar<V>, String>,
1358 count: UnordMap<Symbol, usize>,
1359}
1360
1361impl<V: Eq + Hash + Copy + Into<usize>> PrettyMap<V> {
1362 pub fn new() -> Self {
1363 PrettyMap { map: UnordMap::default(), count: UnordMap::default() }
1364 }
1365
1366 pub fn set(&mut self, var: PrettyVar<V>, prefix: Option<Symbol>) -> String {
1367 if let Some(symbol) = self.map.get(&var) {
1369 return symbol.clone();
1370 }
1371 let symbol = if let Some(prefix) = prefix {
1373 let index = self.count.entry(prefix).or_insert(0);
1374 let symbol = format!("{}{}", prefix, as_subscript(*index));
1375 *index += 1;
1376 symbol
1377 } else {
1378 format!("a'{}", var.as_subscript())
1379 };
1380 self.map.insert(var, symbol.clone());
1381 symbol
1382 }
1383
1384 pub fn get(&self, key: &PrettyVar<V>) -> String {
1385 match self.map.get(key) {
1386 Some(s) => s.clone(),
1387 None => format!("a'{}", key.as_subscript()),
1388 }
1389 }
1390}
1391
1392impl KVar {
1393 pub fn new(kvid: KVid, self_args: usize, args: Vec<Expr>) -> Self {
1394 KVar { kvid, self_args, args: List::from_vec(args) }
1395 }
1396
1397 fn self_args(&self) -> &[Expr] {
1398 &self.args[..self.self_args]
1399 }
1400
1401 fn scope(&self) -> &[Expr] {
1402 &self.args[self.self_args..]
1403 }
1404}
1405
1406impl WKVar {
1407 fn self_args(&self) -> &[Expr] {
1408 &self.args[..self.self_args]
1409 }
1410
1411 fn scope(&self) -> &[Expr] {
1412 &self.args[self.self_args..]
1413 }
1414}
1415
1416impl Var {
1417 pub fn to_expr(&self) -> Expr {
1418 Expr::var(*self)
1419 }
1420
1421 pub fn shift_in(&self, amount: u32) -> Self {
1422 match self {
1423 Var::Bound(idx, breft) => Var::Bound(idx.shifted_in(amount), *breft),
1424 _ => *self,
1425 }
1426 }
1427
1428 pub fn shift_out(&self, amount: u32) -> Self {
1429 match self {
1430 Var::Bound(idx, breft) => Var::Bound(idx.shifted_out(amount), *breft),
1431 _ => *self,
1432 }
1433 }
1434}
1435
1436impl Path {
1437 pub fn new(loc: Loc, projection: impl Into<List<FieldIdx>>) -> Path {
1438 Path { loc, projection: projection.into() }
1439 }
1440
1441 pub fn projection(&self) -> &[FieldIdx] {
1442 &self.projection[..]
1443 }
1444
1445 pub fn to_expr(&self) -> Expr {
1446 self.projection
1447 .iter()
1448 .fold(self.loc.to_expr(), |e, f| Expr::path_proj(e, *f))
1449 }
1450
1451 pub fn to_loc(&self) -> Option<Loc> {
1452 if self.projection.is_empty() { Some(self.loc) } else { None }
1453 }
1454}
1455
1456impl Loc {
1457 pub fn to_expr(&self) -> Expr {
1458 match self {
1459 Loc::Local(local) => Expr::local(*local),
1460 Loc::Var(var) => Expr::var(*var),
1461 }
1462 }
1463}
1464
1465macro_rules! impl_ops {
1466 ($($op:ident: $method:ident),*) => {$(
1467 impl<Rhs> std::ops::$op<Rhs> for Expr
1468 where
1469 Rhs: Into<Expr>,
1470 {
1471 type Output = Expr;
1472
1473 fn $method(self, rhs: Rhs) -> Self::Output {
1474 let sort = crate::rty::Sort::Int;
1475 Expr::binary_op(BinOp::$op(sort), self, rhs)
1476 }
1477 }
1478
1479 impl<Rhs> std::ops::$op<Rhs> for &Expr
1480 where
1481 Rhs: Into<Expr>,
1482 {
1483 type Output = Expr;
1484
1485 fn $method(self, rhs: Rhs) -> Self::Output {
1486 let sort = crate::rty::Sort::Int;
1487 Expr::binary_op(BinOp::$op(sort), self, rhs)
1488 }
1489 }
1490 )*};
1491}
1492impl_ops!(Add: add, Sub: sub, Mul: mul, Div: div);
1493
1494impl From<i32> for Expr {
1495 fn from(value: i32) -> Self {
1496 Expr::constant(Constant::from(value))
1497 }
1498}
1499
1500impl From<&Expr> for Expr {
1501 fn from(e: &Expr) -> Self {
1502 e.clone()
1503 }
1504}
1505
1506impl From<Path> for Expr {
1507 fn from(path: Path) -> Self {
1508 path.to_expr()
1509 }
1510}
1511
1512impl From<Name> for Expr {
1513 fn from(name: Name) -> Self {
1514 Expr::fvar(name)
1515 }
1516}
1517
1518impl From<Var> for Expr {
1519 fn from(var: Var) -> Self {
1520 Expr::var(var)
1521 }
1522}
1523
1524impl From<SpecFuncKind> for Expr {
1525 fn from(kind: SpecFuncKind) -> Self {
1526 Expr::global_func(kind)
1527 }
1528}
1529
1530impl From<InternalFuncKind> for Expr {
1531 fn from(kind: InternalFuncKind) -> Self {
1532 Expr::internal_func(kind)
1533 }
1534}
1535
1536impl From<Loc> for Path {
1537 fn from(loc: Loc) -> Self {
1538 Path::new(loc, vec![])
1539 }
1540}
1541
1542impl From<Name> for Loc {
1543 fn from(name: Name) -> Self {
1544 Loc::Var(Var::Free(name))
1545 }
1546}
1547
1548impl From<Local> for Loc {
1549 fn from(local: Local) -> Self {
1550 Loc::Local(local)
1551 }
1552}
1553
1554#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Encodable, Decodable)]
1555pub struct Real(pub Symbol);
1556
1557#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Encodable, Decodable)]
1558pub enum Constant {
1559 Int(BigInt),
1560 Real(Real),
1561 Bool(bool),
1562 Str(Symbol),
1563 Char(char),
1564 BitVec(u128, u32),
1565}
1566
1567impl Constant {
1568 pub const ZERO: Constant = Constant::Int(BigInt::ZERO);
1569 pub const ONE: Constant = Constant::Int(BigInt::ONE);
1570 pub const TRUE: Constant = Constant::Bool(true);
1571
1572 fn to_bool(self) -> Option<bool> {
1573 match self {
1574 Constant::Bool(b) => Some(b),
1575 _ => None,
1576 }
1577 }
1578
1579 fn to_int(self) -> Option<BigInt> {
1580 match self {
1581 Constant::Int(n) => Some(n),
1582 _ => None,
1583 }
1584 }
1585
1586 pub fn iff(&self, other: &Constant) -> Option<Constant> {
1587 let b1 = self.to_bool()?;
1588 let b2 = other.to_bool()?;
1589 Some(Constant::Bool(b1 == b2))
1590 }
1591
1592 pub fn imp(&self, other: &Constant) -> Option<Constant> {
1593 let b1 = self.to_bool()?;
1594 let b2 = other.to_bool()?;
1595 Some(Constant::Bool(!b1 || b2))
1596 }
1597
1598 pub fn or(&self, other: &Constant) -> Option<Constant> {
1599 let b1 = self.to_bool()?;
1600 let b2 = other.to_bool()?;
1601 Some(Constant::Bool(b1 || b2))
1602 }
1603
1604 pub fn and(&self, other: &Constant) -> Option<Constant> {
1605 let b1 = self.to_bool()?;
1606 let b2 = other.to_bool()?;
1607 Some(Constant::Bool(b1 && b2))
1608 }
1609
1610 pub fn eq(&self, other: &Constant) -> Constant {
1611 Constant::Bool(*self == *other)
1612 }
1613
1614 pub fn ne(&self, other: &Constant) -> Constant {
1615 Constant::Bool(*self != *other)
1616 }
1617
1618 pub fn gt(&self, other: &Constant) -> Option<Constant> {
1619 let n1 = self.to_int()?;
1620 let n2 = other.to_int()?;
1621 Some(Constant::Bool(n1 > n2))
1622 }
1623
1624 pub fn ge(&self, other: &Constant) -> Option<Constant> {
1625 let n1 = self.to_int()?;
1626 let n2 = other.to_int()?;
1627 Some(Constant::Bool(n1 >= n2))
1628 }
1629
1630 pub fn from_scalar_int<'tcx, T>(tcx: TyCtxt<'tcx>, scalar: ScalarInt, t: &T) -> Option<Self>
1631 where
1632 T: ToRustc<'tcx, T = rustc_middle::ty::Ty<'tcx>>,
1633 {
1634 use rustc_middle::ty::TyKind;
1635 let ty = t.to_rustc(tcx);
1636 match ty.kind() {
1637 TyKind::Int(int_ty) => Some(Constant::from(scalar_to_int(tcx, scalar, *int_ty))),
1638 TyKind::Uint(uint_ty) => Some(Constant::from(scalar_to_uint(tcx, scalar, *uint_ty))),
1639 TyKind::Bool => {
1640 let b = scalar_to_bits(tcx, scalar, ty);
1641 Some(Constant::Bool(b != 0))
1642 }
1643 TyKind::Char => {
1644 let b = scalar_to_bits(tcx, scalar, ty);
1645 Some(Constant::Char(char::from_u32(b as u32)?))
1646 }
1647 _ => bug!(),
1648 }
1649 }
1650
1651 pub fn int_min(bit_width: u32) -> Constant {
1653 Constant::Int(BigInt::int_min(bit_width))
1654 }
1655
1656 pub fn int_max(bit_width: u32) -> Constant {
1658 Constant::Int(BigInt::int_max(bit_width))
1659 }
1660
1661 pub fn uint_max(bit_width: u32) -> Constant {
1663 Constant::Int(BigInt::uint_max(bit_width))
1664 }
1665}
1666
1667impl From<i32> for Constant {
1668 fn from(c: i32) -> Self {
1669 Constant::Int(c.into())
1670 }
1671}
1672
1673impl From<usize> for Constant {
1674 fn from(u: usize) -> Self {
1675 Constant::Int(u.into())
1676 }
1677}
1678
1679impl From<u32> for Constant {
1680 fn from(c: u32) -> Self {
1681 Constant::Int(c.into())
1682 }
1683}
1684
1685impl From<u64> for Constant {
1686 fn from(c: u64) -> Self {
1687 Constant::Int(c.into())
1688 }
1689}
1690
1691impl From<u128> for Constant {
1692 fn from(c: u128) -> Self {
1693 Constant::Int(c.into())
1694 }
1695}
1696
1697impl From<i128> for Constant {
1698 fn from(c: i128) -> Self {
1699 Constant::Int(c.into())
1700 }
1701}
1702
1703impl From<bool> for Constant {
1704 fn from(b: bool) -> Self {
1705 Constant::Bool(b)
1706 }
1707}
1708
1709impl From<Symbol> for Constant {
1710 fn from(s: Symbol) -> Self {
1711 Constant::Str(s)
1712 }
1713}
1714
1715impl From<char> for Constant {
1716 fn from(c: char) -> Self {
1717 Constant::Char(c)
1718 }
1719}
1720
1721impl_internable!(ExprKind);
1722impl_slice_internable!(Expr, KVar);
1723
1724#[derive(Debug)]
1725pub struct FieldBind<T> {
1726 pub name: Symbol,
1727 pub value: T,
1728}
1729
1730impl<T: Pretty> Pretty for FieldBind<T> {
1731 fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1732 w!(cx, f, "{}: {:?}", ^self.name, &self.value)
1733 }
1734}
1735
1736pub(crate) mod pretty {
1737
1738 use flux_rustc_bridge::def_id_to_string;
1739
1740 use super::*;
1741 use crate::name_of_thy_func;
1742
1743 #[derive(PartialEq, Eq, PartialOrd, Ord)]
1744 enum Precedence {
1745 Iff,
1746 Imp,
1747 Or,
1748 And,
1749 Cmp,
1750 Bitvec,
1751 AddSub,
1752 MulDiv,
1753 }
1754
1755 impl BinOp {
1756 fn precedence(&self) -> Precedence {
1757 match self {
1758 BinOp::Iff => Precedence::Iff,
1759 BinOp::Imp => Precedence::Imp,
1760 BinOp::Or => Precedence::Or,
1761 BinOp::And => Precedence::And,
1762 BinOp::Eq
1763 | BinOp::Ne
1764 | BinOp::Gt(_)
1765 | BinOp::Lt(_)
1766 | BinOp::Ge(_)
1767 | BinOp::Le(_) => Precedence::Cmp,
1768 BinOp::Add(_) | BinOp::Sub(_) => Precedence::AddSub,
1769 BinOp::Mul(_) | BinOp::Div(_) | BinOp::Mod(_) => Precedence::MulDiv,
1770 BinOp::BitAnd(_)
1771 | BinOp::BitOr(_)
1772 | BinOp::BitShl(_)
1773 | BinOp::BitShr(_)
1774 | BinOp::BitXor(_) => Precedence::Bitvec,
1775 }
1776 }
1777 }
1778
1779 impl Precedence {
1780 pub fn is_associative(&self) -> bool {
1781 !matches!(self, Precedence::Imp | Precedence::Cmp)
1782 }
1783 }
1784
1785 pub fn should_parenthesize(op: &BinOp, child: &Expr) -> bool {
1786 if let ExprKind::BinaryOp(child_op, ..) = child.kind() {
1787 child_op.precedence() < op.precedence()
1788 || (child_op.precedence() == op.precedence() && !op.precedence().is_associative())
1789 } else {
1790 false
1791 }
1792 }
1793
1794 impl Pretty for Ctor {
1795 fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1796 match self {
1797 Ctor::Struct(def_id) => {
1798 w!(cx, f, "{:?}", def_id)
1799 }
1800 Ctor::Enum(def_id, variant_idx) => {
1801 w!(cx, f, "{:?}::{:?}", def_id, ^variant_idx)
1802 }
1803 Ctor::RawPtr => w!(cx, f, "ptr"),
1804 }
1805 }
1806 }
1807
1808 impl Pretty for fhir::QuantKind {
1809 fn fmt(&self, _cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1810 match self {
1811 fhir::QuantKind::Exists => w!(cx, f, "∃"),
1812 fhir::QuantKind::Forall => w!(cx, f, "∀"),
1813 }
1814 }
1815 }
1816
1817 impl Pretty for InternalFuncKind {
1818 fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1819 match self {
1820 InternalFuncKind::Rel(op) => w!(cx, f, "[{:?}]?", op),
1821 InternalFuncKind::Cast => w!(cx, f, "cast"),
1822 }
1823 }
1824 }
1825
1826 impl Pretty for QuantDom {
1827 fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1828 match self {
1829 QuantDom::Bounded { start, end } => w!(cx, f, "in {} .. {}", ^start, ^end),
1830 QuantDom::Unbounded => Ok(()),
1831 }
1832 }
1833 }
1834
1835 impl Pretty for Expr {
1836 fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1837 let e = if cx.simplify_exprs {
1838 self.simplify(&SnapshotMap::default())
1839 } else {
1840 self.clone()
1841 };
1842 match e.kind() {
1843 ExprKind::Var(var) => w!(cx, f, "{:?}", var),
1844 ExprKind::Local(local) => w!(cx, f, "{:?}", ^local),
1845 ExprKind::ConstDefId(did) => w!(cx, f, "{}", ^def_id_to_string(*did)),
1846 ExprKind::Constant(c) => w!(cx, f, "{:?}", c),
1847
1848 ExprKind::BinaryOp(op, e1, e2) => {
1849 if should_parenthesize(op, e1) {
1850 w!(cx, f, "({:?})", e1)?;
1851 } else {
1852 w!(cx, f, "{:?}", e1)?;
1853 }
1854 if matches!(op, BinOp::Div(_)) {
1855 w!(cx, f, "{:?}", op)?;
1856 } else {
1857 w!(cx, f, " {:?} ", op)?;
1858 }
1859 if should_parenthesize(op, e2) {
1860 w!(cx, f, "({:?})", e2)?;
1861 } else {
1862 w!(cx, f, "{:?}", e2)?;
1863 }
1864 Ok(())
1865 }
1866 ExprKind::UnaryOp(op, e) => {
1867 if e.is_atom() {
1868 w!(cx, f, "{:?}{:?}", op, e)
1869 } else {
1870 w!(cx, f, "{:?}({:?})", op, e)
1871 }
1872 }
1873 ExprKind::FieldProj(e, proj) if let ExprKind::Ctor(_, _) = e.kind() => {
1874 w!(cx, f, "{:?}", e.proj_and_reduce(*proj))
1877 }
1878 ExprKind::FieldProj(e, proj) => {
1879 if e.is_atom() {
1880 w!(cx, f, "{:?}.{}", e, ^fmt_field_proj(cx, *proj))
1881 } else {
1882 w!(cx, f, "({:?}).{}", e, ^fmt_field_proj(cx, *proj))
1883 }
1884 }
1885 ExprKind::Tuple(flds) => {
1886 if let [e] = &flds[..] {
1887 w!(cx, f, "({:?},)", e)
1888 } else {
1889 w!(cx, f, "({:?})", join!(", ", flds))
1890 }
1891 }
1892 ExprKind::IsCtor(def_id, variant_idx, idx) => {
1893 w!(cx, f, "({:?} is {:?}::{:?})", idx, def_id, ^variant_idx)
1894 }
1895 ExprKind::Ctor(ctor, flds) => {
1896 if matches!(ctor, Ctor::RawPtr) {
1897 let fields = iter::zip(RawPtrField::iter(), flds)
1898 .map(|(field, value)| {
1899 FieldBind { name: field.symbol(), value: value.clone() }
1900 })
1901 .collect_vec();
1902 return w!(cx, f, "ptr {{ {:?} }}", join!(", ", fields));
1903 }
1904 let Some((def_id, variant_idx)) = ctor.def_id_and_variant() else {
1905 unreachable!()
1906 };
1907 if let Some(adt_sort_def) = cx.adt_sort_def_of(def_id) {
1908 let variant = adt_sort_def.variant(variant_idx).field_names();
1909 let fields = iter::zip(variant, flds)
1910 .map(|(name, value)| FieldBind { name: *name, value: value.clone() })
1911 .collect_vec();
1912 match ctor {
1913 Ctor::Struct(_) => {
1914 w!(cx, f, "{:?} {{ {:?} }}", def_id, join!(", ", fields))
1915 }
1916 Ctor::Enum(_, idx) => {
1917 if fields.is_empty() {
1918 w!(cx, f, "{:?}::{:?}", def_id, ^idx.index())
1919 } else {
1920 w!(cx, f, "{:?}::{:?}({:?})", def_id, ^idx.index(), join!(", ", fields))
1921 }
1922 }
1923 Ctor::RawPtr => unreachable!(),
1924 }
1925 } else {
1926 match ctor {
1927 Ctor::Struct(_) => {
1928 w!(cx, f, "{:?} {{ {:?} }}", def_id, join!(", ", flds))
1929 }
1930 Ctor::Enum(_, idx) => {
1931 w!(cx, f, "{:?}::{:?} {{ {:?} }}", def_id, ^idx, join!(", ", flds))
1932 }
1933 Ctor::RawPtr => unreachable!(),
1934 }
1935 }
1936 }
1937 ExprKind::PathProj(e, field) => {
1938 if e.is_atom() {
1939 w!(cx, f, "{:?}.{:?}", e, field)
1940 } else {
1941 w!(cx, f, "({:?}).{:?}", e, field)
1942 }
1943 }
1944 ExprKind::App(func, _, args) => {
1945 w!(cx, f, "{:?}({})",
1946 parens!(func, !func.is_atom()),
1947 ^args
1948 .iter()
1949 .format_with(", ", |arg, f| f(&format_args_cx!(cx, "{:?}", arg)))
1950 )
1951 }
1952 ExprKind::IfThenElse(p, e1, e2) => {
1953 w!(cx, f, "if {:?} {{ {:?} }} else {{ {:?} }}", p, e1, e2)
1954 }
1955 ExprKind::Hole(_) => {
1956 w!(cx, f, "*")
1957 }
1958 ExprKind::KVar(kvar) => {
1959 w!(cx, f, "{:?}", kvar)
1960 }
1961 ExprKind::WKVar(wkvar) => {
1962 w!(cx, f, "{:?}", wkvar)
1963 }
1964 ExprKind::Alias(alias, args) => {
1965 w!(cx, f, "{:?}({:?})", alias, join!(", ", args))
1966 }
1967 ExprKind::Abs(lam) => {
1968 w!(cx, f, "{:?}", lam)
1969 }
1970 ExprKind::GlobalFunc(SpecFuncKind::Def(did)) => {
1971 w!(cx, f, "{}", ^did.name())
1972 }
1973 ExprKind::GlobalFunc(SpecFuncKind::Thy(itf)) => {
1974 if let Some(name) = name_of_thy_func(*itf) {
1975 w!(cx, f, "{}", ^name)
1976 } else {
1977 w!(cx, f, "<error>")
1978 }
1979 }
1980 ExprKind::InternalFunc(func) => {
1981 w!(cx, f, "{:?}", func)
1982 }
1983 ExprKind::Quant(kind, dom, body) => {
1984 let vars = body.vars();
1985 cx.with_bound_vars(vars, || {
1986 w!(cx, f, "{:?} {:?} {{ {:?} }}", kind, dom, body.skip_binder_ref())
1987 })
1988 }
1989 ExprKind::Let(init, body) => {
1990 let vars = body.vars();
1991 cx.with_bound_vars(vars, || {
1992 cx.fmt_bound_vars(false, "(let ", vars, " = ", f)?;
1993 w!(cx, f, "{:?} in {:?})", init, body.skip_binder_ref())
1994 })
1995 }
1996 }
1997 }
1998 }
1999
2000 fn fmt_field_proj(cx: &PrettyCx, proj: FieldProj) -> String {
2001 if let FieldProj::Adt { def_id, field } = proj
2002 && let Some(adt_sort_def) = cx.adt_sort_def_of(def_id)
2003 {
2004 format!("{}", adt_sort_def.struct_variant().field_names()[field as usize])
2005 } else if let FieldProj::RawPtr { field } = proj {
2006 field.name().to_string()
2007 } else {
2008 format!("{}", proj.field_idx())
2009 }
2010 }
2011
2012 impl Pretty for Constant {
2013 fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2014 match self {
2015 Constant::Int(i) => w!(cx, f, "{i}"),
2016 Constant::BitVec(i, sz) => w!(cx, f, "bv({i}, {sz})"),
2017 Constant::Real(r) => w!(cx, f, "{}", ^r.0),
2018 Constant::Bool(b) => w!(cx, f, "{b}"),
2019 Constant::Str(sym) => w!(cx, f, "\"{sym}\""),
2020 Constant::Char(c) => w!(cx, f, "\'{c}\'"),
2021 }
2022 }
2023 }
2024
2025 impl Pretty for AliasReft {
2026 fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2027 w!(cx, f, "<({:?}) as {:?}", &self.args[0], self.assoc_id.parent())?;
2028 let args = &self.args[1..];
2029 if !args.is_empty() {
2030 w!(cx, f, "<{:?}>", join!(", ", args))?;
2031 }
2032 w!(cx, f, ">::{}", ^self.assoc_id.name())
2033 }
2034 }
2035
2036 impl Pretty for Lambda {
2037 fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2038 let vars = self.body.vars();
2039 cx.with_bound_vars(vars, || {
2042 cx.fmt_bound_vars(false, "λ", vars, ". ", f)?;
2043 w!(cx, f, "{:?}", self.body.as_ref().skip_binder())
2044 })
2045 }
2046 }
2047
2048 impl Pretty for Var {
2049 fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2050 match self {
2051 Var::Bound(debruijn, var) => cx.fmt_bound_reft(*debruijn, *var, f),
2052 Var::EarlyParam(var) => w!(cx, f, "{}", ^var.name),
2053 Var::Free(name) => w!(cx, f, "{:?}", ^name),
2054 Var::EVar(evar) => w!(cx, f, "{:?}", ^evar),
2055 Var::ConstGeneric(param) => w!(cx, f, "{}", ^param.name),
2056 }
2057 }
2058 }
2059
2060 impl Pretty for KVar {
2061 fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2062 w!(cx, f, "{:?}", ^self.kvid)?;
2063 match cx.kvar_args {
2064 KVarArgs::All => {
2065 w!(
2066 cx,
2067 f,
2068 "({:?})[{:?}]",
2069 join!(", ", self.self_args()),
2070 join!(", ", self.scope())
2071 )?;
2072 }
2073 KVarArgs::SelfOnly => w!(cx, f, "({:?})", join!(", ", self.self_args()))?,
2074 KVarArgs::Hide => {}
2075 }
2076 Ok(())
2077 }
2078 }
2079
2080 impl Pretty for WKVar {
2081 fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2082 w!(cx, f, "$wk{}_{}", ^self.wkvid.id.index(), ^cx.tcx().def_path_str(self.wkvid.parent_fn))?;
2085 w!(cx, f, "({:?})[{:?}]", join!(", ", self.self_args()), join!(", ", self.scope()))?;
2086 Ok(())
2087 }
2088 }
2089
2090 impl Pretty for Path {
2091 fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2092 w!(cx, f, "{:?}", &self.loc)?;
2093 for field in &self.projection {
2094 w!(cx, f, ".{}", ^u32::from(*field))?;
2095 }
2096 Ok(())
2097 }
2098 }
2099
2100 impl Pretty for Loc {
2101 fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2102 match self {
2103 Loc::Local(local) => w!(cx, f, "{:?}", ^local),
2104 Loc::Var(var) => w!(cx, f, "{:?}", var),
2105 }
2106 }
2107 }
2108
2109 impl Pretty for BinOp {
2110 fn fmt(&self, _cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2111 match self {
2112 BinOp::Iff => w!(cx, f, "<=>"),
2113 BinOp::Imp => w!(cx, f, "=>"),
2114 BinOp::Or => w!(cx, f, "||"),
2115 BinOp::And => w!(cx, f, "&&"),
2116 BinOp::Eq => w!(cx, f, "=="),
2117 BinOp::Ne => w!(cx, f, "!="),
2118 BinOp::Gt(_) => w!(cx, f, ">"),
2119 BinOp::Ge(_) => w!(cx, f, ">="),
2120 BinOp::Lt(_) => w!(cx, f, "<"),
2121 BinOp::Le(_) => w!(cx, f, "<="),
2122 BinOp::Add(_) => w!(cx, f, "+"),
2123 BinOp::Sub(_) => w!(cx, f, "-"),
2124 BinOp::Mul(_) => w!(cx, f, "*"),
2125 BinOp::Div(_) => w!(cx, f, "/"),
2126 BinOp::Mod(_) => w!(cx, f, "mod"),
2127 BinOp::BitAnd(_) => w!(cx, f, "&"),
2128 BinOp::BitOr(_) => w!(cx, f, "|"),
2129 BinOp::BitXor(_) => w!(cx, f, "^"),
2130 BinOp::BitShl(_) => w!(cx, f, "<<"),
2131 BinOp::BitShr(_) => w!(cx, f, ">>"),
2132 }
2133 }
2134 }
2135
2136 impl Pretty for UnOp {
2137 fn fmt(&self, _cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2138 match self {
2139 UnOp::Not => w!(cx, f, "!"),
2140 UnOp::Neg => w!(cx, f, "-"),
2141 }
2142 }
2143 }
2144
2145 impl_debug_with_default_cx!(Expr, Loc, Path, Var, KVar, WKVar, Lambda, AliasReft);
2146
2147 impl PrettyNested for Lambda {
2148 fn fmt_nested(&self, cx: &PrettyCx) -> Result<NestedString, fmt::Error> {
2149 cx.nested_with_bound_vars("λ", self.body.vars(), None, |prefix| {
2151 let expr_d = self.body.skip_binder_ref().fmt_nested(cx)?;
2152 let text = format!("{}{}", prefix, expr_d.text);
2153 Ok(NestedString { text, children: expr_d.children, key: None })
2154 })
2155 }
2156 }
2157
2158 pub fn aggregate_nested(
2159 cx: &PrettyCx,
2160 ctor: &Ctor,
2161 flds: &[Expr],
2162 is_named: bool,
2163 ) -> Result<NestedString, fmt::Error> {
2164 let mut text =
2165 if is_named && ctor.is_enum() { format_cx!(cx, "{:?}", ctor) } else { "".to_string() };
2166 if flds.is_empty() {
2167 Ok(NestedString { text, children: None, key: None })
2169 } else if flds.len() == 1 {
2170 text += &flds[0].fmt_nested(cx)?.text;
2172 Ok(NestedString { text, children: None, key: None })
2173 } else {
2174 let keys = if let Some((def_id, variant_idx)) = ctor.def_id_and_variant()
2175 && let Some(adt_sort_def) = cx.adt_sort_def_of(def_id)
2176 {
2177 adt_sort_def
2178 .variant(variant_idx)
2179 .field_names()
2180 .iter()
2181 .map(|name| format!("{name}"))
2182 .collect_vec()
2183 } else if matches!(ctor, Ctor::RawPtr) {
2184 RawPtrField::iter()
2185 .map(|field| field.name().to_string())
2186 .collect_vec()
2187 } else {
2188 (0..flds.len()).map(|i| format!("arg{i}")).collect_vec()
2189 };
2190 text += "{..}";
2192 let mut children = vec![];
2193 for (key, fld) in iter::zip(keys, flds) {
2194 let fld_d = fld.fmt_nested(cx)?;
2195 children.push(NestedString { key: Some(key), ..fld_d });
2196 }
2197 Ok(NestedString { text, children: Some(children), key: None })
2198 }
2199 }
2200
2201 impl PrettyNested for Name {
2202 fn fmt_nested(&self, cx: &PrettyCx) -> Result<NestedString, fmt::Error> {
2203 let text = cx.pretty_var_env.get(&PrettyVar::Local(*self));
2204 Ok(NestedString { text, key: None, children: None })
2205 }
2206 }
2207
2208 impl PrettyNested for Expr {
2209 fn fmt_nested(&self, cx: &PrettyCx) -> Result<NestedString, fmt::Error> {
2210 let e = if cx.simplify_exprs {
2211 self.simplify(&SnapshotMap::default())
2212 } else {
2213 self.clone()
2214 };
2215 match e.kind() {
2216 ExprKind::Var(Var::Free(name)) => name.fmt_nested(cx),
2217 ExprKind::Var(..)
2218 | ExprKind::Local(..)
2219 | ExprKind::Constant(..)
2220 | ExprKind::ConstDefId(..)
2221 | ExprKind::Hole(..)
2222 | ExprKind::GlobalFunc(..)
2223 | ExprKind::InternalFunc(..) => debug_nested(cx, &e),
2224 ExprKind::WKVar(..) => debug_nested(cx, &e),
2225 ExprKind::KVar(kvar) => {
2226 let kv = format!("{:?}", kvar.kvid);
2227 let mut strs = vec![kv];
2228 for arg in &kvar.args {
2229 strs.push(arg.fmt_nested(cx)?.text);
2230 }
2231 let text = format!("##[{}]##", strs.join("##"));
2232 Ok(NestedString { text, children: None, key: None })
2233 }
2234 ExprKind::IfThenElse(p, e1, e2) => {
2235 let p_d = p.fmt_nested(cx)?;
2236 let e1_d = e1.fmt_nested(cx)?;
2237 let e2_d = e2.fmt_nested(cx)?;
2238 let text = format!("(if {} then {} else {})", p_d.text, e1_d.text, e2_d.text);
2239 let children = float_children(vec![p_d.children, e1_d.children, e2_d.children]);
2240 Ok(NestedString { text, children, key: None })
2241 }
2242 ExprKind::BinaryOp(op, e1, e2) => {
2243 let e1_d = e1.fmt_nested(cx)?;
2244 let e2_d = e2.fmt_nested(cx)?;
2245 let e1_text = if should_parenthesize(op, e1) {
2246 format!("({})", e1_d.text)
2247 } else {
2248 e1_d.text
2249 };
2250 let e2_text = if should_parenthesize(op, e2) {
2251 format!("({})", e2_d.text)
2252 } else {
2253 e2_d.text
2254 };
2255 let op_d = debug_nested(cx, op)?;
2256 let op_text = if matches!(op, BinOp::Div(_)) {
2257 op_d.text
2258 } else {
2259 format!(" {} ", op_d.text)
2260 };
2261 let text = format!("{e1_text}{op_text}{e2_text}");
2262 let children = float_children(vec![e1_d.children, e2_d.children]);
2263 Ok(NestedString { text, children, key: None })
2264 }
2265 ExprKind::UnaryOp(op, e) => {
2266 let e_d = e.fmt_nested(cx)?;
2267 let op_d = debug_nested(cx, op)?;
2268 let text = if e.is_atom() {
2269 format!("{}{}", op_d.text, e_d.text)
2270 } else {
2271 format!("{}({})", op_d.text, e_d.text)
2272 };
2273 Ok(NestedString { text, children: e_d.children, key: None })
2274 }
2275 ExprKind::FieldProj(e, proj) if let ExprKind::Ctor(_, _) = e.kind() => {
2276 e.proj_and_reduce(*proj).fmt_nested(cx)
2279 }
2280 ExprKind::FieldProj(e, proj) => {
2281 let e_d = e.fmt_nested(cx)?;
2282 let text = if e.is_atom() {
2283 format!("{}.{}", e_d.text, fmt_field_proj(cx, *proj))
2284 } else {
2285 format!("({}).{}", e_d.text, fmt_field_proj(cx, *proj))
2286 };
2287 Ok(NestedString { text, children: e_d.children, key: None })
2288 }
2289 ExprKind::Tuple(flds) => {
2290 let mut texts = vec![];
2291 let mut kidss = vec![];
2292 for e in flds {
2293 let e_d = e.fmt_nested(cx)?;
2294 texts.push(e_d.text);
2295 kidss.push(e_d.children);
2296 }
2297 let text = if let [e] = &texts[..] {
2298 format!("({e},)")
2299 } else {
2300 format!("({})", texts.join(", "))
2301 };
2302 let children = float_children(kidss);
2303 Ok(NestedString { text, children, key: None })
2304 }
2305 ExprKind::Ctor(ctor, flds) => aggregate_nested(cx, ctor, flds, true),
2306 ExprKind::IsCtor(def_id, variant_idx, idx) => {
2307 let text = format!("is::{:?}::{:?}( {:?} )", def_id, variant_idx, idx);
2308 Ok(NestedString { text, children: None, key: None })
2309 }
2310 ExprKind::PathProj(e, field) => {
2311 let e_d = e.fmt_nested(cx)?;
2312 let text = if e.is_atom() {
2313 format!("{}.{:?}", e_d.text, field)
2314 } else {
2315 format!("({}).{:?}", e_d.text, field)
2316 };
2317 Ok(NestedString { text, children: e_d.children, key: None })
2318 }
2319 ExprKind::Alias(alias, args) => {
2320 let mut texts = vec![];
2321 let mut kidss = vec![];
2322 for arg in args {
2323 let arg_d = arg.fmt_nested(cx)?;
2324 texts.push(arg_d.text);
2325 kidss.push(arg_d.children);
2326 }
2327 let text = format_cx!(cx, "{:?}({:?})", alias, texts.join(", "));
2328 let children = float_children(kidss);
2329 Ok(NestedString { text, children, key: None })
2330 }
2331 ExprKind::App(func, _, args) => {
2332 let func_d = func.fmt_nested(cx)?;
2333 let mut texts = vec![];
2334 let mut kidss = vec![func_d.children];
2335 for arg in args {
2336 let arg_d = arg.fmt_nested(cx)?;
2337 texts.push(arg_d.text);
2338 kidss.push(arg_d.children);
2339 }
2340 let text = if func.is_atom() {
2341 format!("{}({})", func_d.text, texts.join(", "))
2342 } else {
2343 format!("({})({})", func_d.text, texts.join(", "))
2344 };
2345 let children = float_children(kidss);
2346 Ok(NestedString { text, children, key: None })
2347 }
2348 ExprKind::Abs(lambda) => lambda.fmt_nested(cx),
2349 ExprKind::Let(init, body) => {
2350 cx.nested_with_bound_vars("let", body.vars(), None, |prefix| {
2352 let body = body.skip_binder_ref().fmt_nested(cx)?;
2353 let text = format!("{:?} {}{}", init, prefix, body.text);
2354 Ok(NestedString { text, children: body.children, key: None })
2355 })
2356 }
2357 ExprKind::Quant(kind, dom, body) => {
2358 let left = match kind {
2359 fhir::QuantKind::Forall => "∀",
2360 fhir::QuantKind::Exists => "∃",
2361 };
2362 let right = Some(format!(" {:?}", dom));
2363
2364 cx.nested_with_bound_vars(left, body.vars(), right, |all_str| {
2365 let expr_d = body.as_ref().skip_binder().fmt_nested(cx)?;
2366 let text = format!("{}{}", all_str, expr_d.text);
2367 Ok(NestedString { text, children: expr_d.children, key: None })
2368 })
2369 }
2370 }
2371 }
2372 }
2373}
2374
2375impl Expr {
2376 pub fn prettify(&self) -> Self {
2378 self.fold_constants()
2379 .push_negations()
2380 .simplify_arithmetic()
2381 .simplify_bounds()
2382 }
2383
2384 pub fn fold_constants(&self) -> Self {
2386 let span = self.span();
2387 match self.kind() {
2388 ExprKind::UnaryOp(op, a) => {
2389 let a_fold = a.fold_constants();
2390
2391 if let ExprKind::Constant(c) = a_fold.kind() {
2392 match (op, c) {
2393 (UnOp::Not, Constant::Bool(b)) => {
2394 return Expr::constant(Constant::Bool(!b)).at_opt(span);
2395 }
2396 (UnOp::Neg, Constant::Int(n)) => {
2397 return Expr::constant(Constant::Int(n.neg())).at_opt(span);
2398 }
2399 _ => {}
2400 }
2401 }
2402 Expr::unary_op(*op, a_fold).at_opt(span)
2403 }
2404
2405 ExprKind::BinaryOp(op, a, b) => {
2406 let a_fold = a.fold_constants();
2407 let b_fold = b.fold_constants();
2408
2409 if let (ExprKind::Constant(c1), ExprKind::Constant(c2)) =
2410 (a_fold.kind(), b_fold.kind())
2411 {
2412 if let Some(c3) = Expr::const_op(op, c1, c2) {
2414 return Expr::constant(c3).at_opt(span);
2415 }
2416
2417 if let (Constant::Int(n1), Constant::Int(n2)) = (c1, c2) {
2419 let result = match op {
2420 BinOp::Add(_) => n1.checked_add(n2),
2421 BinOp::Sub(_) => n1.checked_sub(n2),
2422 BinOp::Mul(_) => n1.checked_mul(n2),
2423 BinOp::Div(_) => n1.checked_div(n2),
2424 BinOp::Mod(_) => n1.checked_rem(n2),
2425 _ => None,
2426 };
2427
2428 if let Some(res) = result {
2429 return Expr::constant(Constant::Int(res)).at_opt(span);
2430 }
2431 }
2432 }
2433
2434 Expr::binary_op(op.clone(), a_fold, b_fold).at_opt(span)
2435 }
2436
2437 ExprKind::IfThenElse(p, e1, e2) => {
2438 let p_fold = p.fold_constants();
2439
2440 if let ExprKind::Constant(Constant::Bool(b)) = p_fold.kind() {
2442 if *b {
2443 return e1.fold_constants().at_opt(span);
2444 } else {
2445 return e2.fold_constants().at_opt(span);
2446 }
2447 }
2448
2449 Expr::ite(p_fold, e1.fold_constants(), e2.fold_constants()).at_opt(span)
2450 }
2451
2452 _ => self.clone(),
2455 }
2456 }
2457
2458 pub fn push_negations(&self) -> Self {
2460 let span = self.span();
2461 match self.kind() {
2462 ExprKind::UnaryOp(UnOp::Not, inner) => {
2463 match inner.kind() {
2464 ExprKind::UnaryOp(UnOp::Not, a) => a.push_negations().at_opt(span),
2466
2467 ExprKind::BinaryOp(BinOp::Le(s), a, b) => {
2469 Expr::binary_op(
2470 BinOp::Gt(s.clone()),
2471 a.push_negations(),
2472 b.push_negations(),
2473 )
2474 .at_opt(span)
2475 }
2476 ExprKind::BinaryOp(BinOp::Lt(s), a, b) => {
2477 Expr::binary_op(
2478 BinOp::Ge(s.clone()),
2479 a.push_negations(),
2480 b.push_negations(),
2481 )
2482 .at_opt(span)
2483 }
2484 ExprKind::BinaryOp(BinOp::Ge(s), a, b) => {
2485 Expr::binary_op(
2486 BinOp::Lt(s.clone()),
2487 a.push_negations(),
2488 b.push_negations(),
2489 )
2490 .at_opt(span)
2491 }
2492 ExprKind::BinaryOp(BinOp::Gt(s), a, b) => {
2493 Expr::binary_op(
2494 BinOp::Le(s.clone()),
2495 a.push_negations(),
2496 b.push_negations(),
2497 )
2498 .at_opt(span)
2499 }
2500
2501 ExprKind::BinaryOp(BinOp::Eq, a, b) => {
2503 Expr::binary_op(BinOp::Ne, a.push_negations(), b.push_negations())
2504 .at_opt(span)
2505 }
2506 ExprKind::BinaryOp(BinOp::Ne, a, b) => {
2507 Expr::binary_op(BinOp::Eq, a.push_negations(), b.push_negations())
2508 .at_opt(span)
2509 }
2510
2511 ExprKind::BinaryOp(BinOp::Or, a, b) => {
2513 Expr::binary_op(
2514 BinOp::And,
2515 a.not().push_negations(),
2516 b.not().push_negations(),
2517 )
2518 .at_opt(span)
2519 }
2520 ExprKind::BinaryOp(BinOp::And, a, b) => {
2521 Expr::binary_op(
2522 BinOp::Or,
2523 a.not().push_negations(),
2524 b.not().push_negations(),
2525 )
2526 .at_opt(span)
2527 }
2528
2529 _ => Expr::unary_op(UnOp::Not, inner.push_negations()).at_opt(span),
2531 }
2532 }
2533 ExprKind::BinaryOp(op, a, b) => {
2534 Expr::binary_op(op.clone(), a.push_negations(), b.push_negations()).at_opt(span)
2535 }
2536 ExprKind::UnaryOp(op, a) => Expr::unary_op(*op, a.push_negations()).at_opt(span),
2537 ExprKind::IfThenElse(p, e1, e2) => {
2538 Expr::ite(p.push_negations(), e1.push_negations(), e2.push_negations()).at_opt(span)
2539 }
2540 _ => self.clone(),
2541 }
2542 }
2543
2544 pub fn simplify_arithmetic(&self) -> Self {
2546 let span = self.span();
2547 match self.kind() {
2548 ExprKind::BinaryOp(BinOp::Mul(s), a, b) => {
2549 let a_simp = a.simplify_arithmetic();
2550 let b_simp = b.simplify_arithmetic();
2551
2552 let is_minus_one = |e: &Expr| matches!(e.kind(), ExprKind::Constant(c) if *c == Constant::from(-1));
2553
2554 if is_minus_one(&b_simp) {
2555 return a_simp.neg().at_opt(span);
2556 }
2557 if is_minus_one(&a_simp) {
2558 return b_simp.neg().at_opt(span);
2559 }
2560
2561 Expr::binary_op(BinOp::Mul(s.clone()), a_simp, b_simp).at_opt(span)
2562 }
2563 ExprKind::BinaryOp(BinOp::Add(s), a, b) => {
2564 let a_simp = a.simplify_arithmetic();
2565 let b_simp = b.simplify_arithmetic();
2566
2567 if let ExprKind::UnaryOp(UnOp::Neg, x) = a_simp.kind() {
2568 return Expr::binary_op(BinOp::Sub(s.clone()), b_simp, x.clone()).at_opt(span);
2569 }
2570 if let ExprKind::UnaryOp(UnOp::Neg, y) = b_simp.kind() {
2571 return Expr::binary_op(BinOp::Sub(s.clone()), a_simp, y.clone()).at_opt(span);
2572 }
2573
2574 Expr::binary_op(BinOp::Add(s.clone()), a_simp, b_simp).at_opt(span)
2575 }
2576 ExprKind::BinaryOp(op, a, b) => {
2577 Expr::binary_op(op.clone(), a.simplify_arithmetic(), b.simplify_arithmetic())
2578 .at_opt(span)
2579 }
2580 ExprKind::UnaryOp(op, a) => Expr::unary_op(*op, a.simplify_arithmetic()).at_opt(span),
2581 ExprKind::IfThenElse(p, e1, e2) => {
2582 Expr::ite(
2583 p.simplify_arithmetic(),
2584 e1.simplify_arithmetic(),
2585 e2.simplify_arithmetic(),
2586 )
2587 .at_opt(span)
2588 }
2589 _ => self.clone(),
2590 }
2591 }
2592
2593 pub fn simplify_bounds(&self) -> Self {
2595 let span = self.span();
2596 match self.kind() {
2597 ExprKind::BinaryOp(op, a, b) => {
2598 let a_simp = a.simplify_bounds();
2599 let b_simp = b.simplify_bounds();
2600
2601 let is_minus_one = |e: &Expr| matches!(e.kind(), ExprKind::Constant(c) if *c == Constant::from(-1));
2602 let is_zero =
2603 |e: &Expr| matches!(e.kind(), ExprKind::Constant(c) if *c == Constant::from(0));
2604
2605 match op {
2607 BinOp::Gt(Sort::Int) => {
2608 if is_minus_one(&b_simp) {
2610 return Expr::binary_op(BinOp::Ge(Sort::Int), a_simp, Expr::zero())
2611 .at_opt(span)
2612 .simplify_bounds();
2613 }
2614 if is_zero(&b_simp)
2616 && let ExprKind::BinaryOp(BinOp::Sub(s_sub), x, y) = a_simp.kind()
2617 {
2618 return Expr::binary_op(BinOp::Gt(s_sub.clone()), x.clone(), y.clone())
2619 .at_opt(span);
2620 }
2621 }
2622 BinOp::Ge(Sort::Int) => {
2623 if is_zero(&b_simp)
2625 && let ExprKind::BinaryOp(BinOp::Sub(s_sub), x, y) = a_simp.kind()
2626 {
2627 return Expr::binary_op(BinOp::Ge(s_sub.clone()), x.clone(), y.clone())
2628 .at_opt(span);
2629 }
2630 }
2631 BinOp::Lt(Sort::Int) => {
2632 if is_zero(&b_simp)
2634 && let ExprKind::BinaryOp(BinOp::Sub(s_sub), x, y) = a_simp.kind()
2635 {
2636 return Expr::binary_op(BinOp::Lt(s_sub.clone()), x.clone(), y.clone())
2637 .at_opt(span);
2638 }
2639 }
2640 BinOp::Le(Sort::Int) => {
2641 if is_minus_one(&b_simp) {
2643 return Expr::binary_op(BinOp::Lt(Sort::Int), a_simp, Expr::zero())
2644 .at_opt(span)
2645 .simplify_bounds();
2646 }
2647 if is_zero(&b_simp)
2649 && let ExprKind::BinaryOp(BinOp::Sub(s_sub), x, y) = a_simp.kind()
2650 {
2651 return Expr::binary_op(BinOp::Le(s_sub.clone()), x.clone(), y.clone())
2652 .at_opt(span);
2653 }
2654 }
2655 _ => {}
2656 }
2657
2658 Expr::binary_op(op.clone(), a_simp, b_simp).at_opt(span)
2659 }
2660 ExprKind::UnaryOp(op, a) => Expr::unary_op(*op, a.simplify_bounds()).at_opt(span),
2661 ExprKind::IfThenElse(p, e1, e2) => {
2662 Expr::ite(p.simplify_bounds(), e1.simplify_bounds(), e2.simplify_bounds())
2663 .at_opt(span)
2664 }
2665 _ => self.clone(),
2666 }
2667 }
2668}