1use std::{fmt, iter, ops::ControlFlow, sync::OnceLock};
2
3use flux_arc_interner::{Interned, List, impl_internable, impl_slice_internable};
4use flux_common::bug;
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 itertools::Itertools;
12use liquid_fixpoint::ThyFunc;
13use rustc_abi::{FIRST_VARIANT, FieldIdx};
14use rustc_data_structures::snapshot_map::SnapshotMap;
15use rustc_hir::def_id::DefId;
16use rustc_index::newtype_index;
17use rustc_macros::{Decodable, Encodable, TyDecodable, TyEncodable};
18use rustc_middle::{
19 mir::Local,
20 ty::{ParamConst, ScalarInt, TyCtxt},
21};
22use rustc_span::{Span, Symbol};
23use rustc_type_ir::{BoundVar, DebruijnIndex, INNERMOST};
24
25use super::{
26 BaseTy, Binder, BoundReftKind, BoundVariableKinds, FuncSort, GenericArgs, GenericArgsExt as _,
27 IntTy, Sort, UintTy,
28};
29use crate::{
30 big_int::BigInt,
31 def_id::FluxDefId,
32 fhir::{self},
33 global_env::GlobalEnv,
34 pretty::*,
35 queries::QueryResult,
36 rty::{
37 BoundVariableKind, SortArg,
38 fold::{
39 TypeFoldable, TypeFolder, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable as _,
40 TypeVisitor,
41 },
42 },
43};
44
45#[derive(Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, TypeVisitable, TypeFoldable)]
48pub struct Lambda {
49 body: Binder<Expr>,
50 output: Sort,
51}
52
53impl Lambda {
54 pub fn bind_with_vars(body: Expr, inputs: BoundVariableKinds, output: Sort) -> Self {
55 debug_assert!(inputs.iter().all(BoundVariableKind::is_refine));
56 Self { body: Binder::bind_with_vars(body, inputs), output }
57 }
58
59 pub fn bind_with_fsort(body: Expr, fsort: FuncSort) -> Self {
60 Self { body: Binder::bind_with_sorts(body, fsort.inputs()), output: fsort.output().clone() }
61 }
62
63 pub fn apply(&self, args: &[Expr]) -> Expr {
64 self.body.replace_bound_refts(args)
65 }
66
67 pub fn vars(&self) -> &BoundVariableKinds {
68 self.body.vars()
69 }
70
71 pub fn output(&self) -> Sort {
72 self.output.clone()
73 }
74
75 pub fn fsort(&self) -> FuncSort {
76 let inputs_and_output = self
77 .vars()
78 .iter()
79 .map(|kind| kind.expect_sort().clone())
80 .chain(iter::once(self.output()))
81 .collect();
82 FuncSort { inputs_and_output }
83 }
84}
85
86#[derive(Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, TypeVisitable, TypeFoldable)]
87pub struct AliasReft {
88 pub assoc_id: FluxDefId,
90 pub args: GenericArgs,
91}
92
93impl AliasReft {
94 pub fn to_rustc_trait_ref<'tcx>(&self, tcx: TyCtxt<'tcx>) -> rustc_middle::ty::TraitRef<'tcx> {
95 let trait_def_id = self.assoc_id.parent();
96 let args = self
97 .args
98 .to_rustc(tcx)
99 .truncate_to(tcx, tcx.generics_of(trait_def_id));
100 rustc_middle::ty::TraitRef::new(tcx, trait_def_id, args)
101 }
102}
103
104#[derive(Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
105pub struct Expr {
106 kind: Interned<ExprKind>,
107 espan: Option<ESpan>,
108}
109
110impl Expr {
111 pub fn at_opt(self, espan: Option<ESpan>) -> Expr {
112 Expr { kind: self.kind, espan }
113 }
114
115 pub fn at(self, espan: ESpan) -> Expr {
116 self.at_opt(Some(espan))
117 }
118
119 pub fn at_base(self, base: ESpan) -> Expr {
120 if let Some(espan) = self.espan { self.at(espan.with_base(base)) } else { self }
121 }
122
123 pub fn span(&self) -> Option<ESpan> {
124 self.espan
125 }
126
127 pub fn tt() -> Expr {
128 static TRUE: OnceLock<Expr> = OnceLock::new();
129 TRUE.get_or_init(|| ExprKind::Constant(Constant::Bool(true)).intern())
130 .clone()
131 }
132
133 pub fn ff() -> Expr {
134 static FALSE: OnceLock<Expr> = OnceLock::new();
135 FALSE
136 .get_or_init(|| ExprKind::Constant(Constant::Bool(false)).intern())
137 .clone()
138 }
139
140 pub fn and_from_iter(exprs: impl IntoIterator<Item = Expr>) -> Expr {
141 exprs
142 .into_iter()
143 .reduce(|acc, e| Expr::binary_op(BinOp::And, acc, e))
144 .unwrap_or_else(Expr::tt)
145 }
146
147 pub fn or_from_iter(exprs: impl IntoIterator<Item = Expr>) -> Expr {
148 exprs
149 .into_iter()
150 .reduce(|acc, e| Expr::binary_op(BinOp::Or, acc, e))
151 .unwrap_or_else(Expr::ff)
152 }
153
154 pub fn and(e1: impl Into<Expr>, e2: impl Into<Expr>) -> Expr {
155 Expr::and_from_iter([e1.into(), e2.into()])
156 }
157
158 pub fn or(e1: impl Into<Expr>, e2: impl Into<Expr>) -> Expr {
159 Expr::or_from_iter([e1.into(), e2.into()])
160 }
161
162 pub fn zero() -> Expr {
163 static ZERO: OnceLock<Expr> = OnceLock::new();
164 ZERO.get_or_init(|| ExprKind::Constant(Constant::ZERO).intern())
165 .clone()
166 }
167
168 pub fn int_max(int_ty: IntTy) -> Expr {
169 let bit_width: u64 = int_ty
170 .bit_width()
171 .unwrap_or(flux_config::pointer_width().bits());
172 Expr::constant(Constant::int_max(bit_width.try_into().unwrap()))
173 }
174
175 pub fn int_min(int_ty: IntTy) -> Expr {
176 let bit_width: u64 = int_ty
177 .bit_width()
178 .unwrap_or(flux_config::pointer_width().bits());
179 Expr::constant(Constant::int_min(bit_width.try_into().unwrap()))
180 }
181
182 pub fn uint_max(uint_ty: UintTy) -> Expr {
183 let bit_width: u64 = uint_ty
184 .bit_width()
185 .unwrap_or(flux_config::pointer_width().bits());
186 Expr::constant(Constant::uint_max(bit_width.try_into().unwrap()))
187 }
188
189 pub fn nu() -> Expr {
190 Expr::bvar(INNERMOST, BoundVar::ZERO, BoundReftKind::Anon)
191 }
192
193 pub fn is_nu(&self) -> bool {
194 if let ExprKind::Var(Var::Bound(INNERMOST, var)) = self.kind()
195 && var.var == BoundVar::ZERO
196 {
197 true
198 } else {
199 false
200 }
201 }
202
203 pub fn unit() -> Expr {
204 Expr::tuple(List::empty())
205 }
206
207 pub fn var(var: Var) -> Expr {
208 ExprKind::Var(var).intern()
209 }
210
211 pub fn fvar(name: Name) -> Expr {
212 Var::Free(name).to_expr()
213 }
214
215 pub fn evar(evid: EVid) -> Expr {
216 Var::EVar(evid).to_expr()
217 }
218
219 pub fn bvar(debruijn: DebruijnIndex, var: BoundVar, kind: BoundReftKind) -> Expr {
220 Var::Bound(debruijn, BoundReft { var, kind }).to_expr()
221 }
222
223 pub fn early_param(index: u32, name: Symbol) -> Expr {
224 Var::EarlyParam(EarlyReftParam { index, name }).to_expr()
225 }
226
227 pub fn local(local: Local) -> Expr {
228 ExprKind::Local(local).intern()
229 }
230
231 pub fn constant(c: Constant) -> Expr {
232 ExprKind::Constant(c).intern()
233 }
234
235 pub fn const_def_id(c: DefId) -> Expr {
236 ExprKind::ConstDefId(c).intern()
237 }
238
239 pub fn const_generic(param: ParamConst) -> Expr {
240 ExprKind::Var(Var::ConstGeneric(param)).intern()
241 }
242
243 pub fn tuple(flds: List<Expr>) -> Expr {
244 ExprKind::Tuple(flds).intern()
245 }
246
247 pub fn ctor_struct(def_id: DefId, flds: List<Expr>) -> Expr {
248 ExprKind::Ctor(Ctor::Struct(def_id), flds).intern()
249 }
250
251 pub fn ctor_enum(def_id: DefId, idx: VariantIdx) -> Expr {
252 ExprKind::Ctor(Ctor::Enum(def_id, idx), List::empty()).intern()
253 }
254
255 pub fn ctor(ctor: Ctor, flds: List<Expr>) -> Expr {
256 ExprKind::Ctor(ctor, flds).intern()
257 }
258
259 pub fn is_ctor(def_id: DefId, variant_idx: VariantIdx, idx: impl Into<Expr>) -> Expr {
260 ExprKind::IsCtor(def_id, variant_idx, idx.into()).intern()
261 }
262
263 pub fn from_bits(bty: &BaseTy, bits: u128) -> Expr {
264 match bty {
266 BaseTy::Int(_) => {
267 let bits = bits as i128;
268 ExprKind::Constant(Constant::from(bits)).intern()
269 }
270 BaseTy::Uint(_) => ExprKind::Constant(Constant::from(bits)).intern(),
271 BaseTy::Bool => ExprKind::Constant(Constant::Bool(bits != 0)).intern(),
272 BaseTy::Char => {
273 let c = char::from_u32(bits.try_into().unwrap()).unwrap();
274 ExprKind::Constant(Constant::Char(c)).intern()
275 }
276 _ => bug!(),
277 }
278 }
279
280 pub fn ite(p: impl Into<Expr>, e1: impl Into<Expr>, e2: impl Into<Expr>) -> Expr {
281 ExprKind::IfThenElse(p.into(), e1.into(), e2.into()).intern()
282 }
283
284 fn empty() -> Expr {
285 let func = Self::global_func(SpecFuncKind::Thy(ThyFunc::SetEmpty));
286 Expr::app(func, List::empty(), List::from_arr([Expr::zero()]))
287 }
288
289 fn singleton(elem: Expr) -> Expr {
290 let func = Self::global_func(SpecFuncKind::Thy(ThyFunc::SetSng));
291 Expr::app(func, List::empty(), List::from_arr([elem]))
292 }
293
294 fn union(expr1: Expr, expr2: Expr) -> Expr {
295 let func = Self::global_func(SpecFuncKind::Thy(ThyFunc::SetCup));
296 Expr::app(func, List::empty(), List::from_arr([expr1, expr2]))
297 }
298
299 pub fn set(elems: List<Expr>) -> Expr {
300 let mut expr = Expr::empty();
301 for elem in &elems {
302 expr = Self::union(expr, Self::singleton(elem.clone()));
303 }
304 expr
305 }
306
307 pub fn abs(lam: Lambda) -> Expr {
308 ExprKind::Abs(lam).intern()
309 }
310
311 pub fn let_(init: Expr, body: Binder<Expr>) -> Expr {
312 ExprKind::Let(init, body).intern()
313 }
314
315 pub fn bounded_quant(kind: fhir::QuantKind, rng: fhir::Range, body: Binder<Expr>) -> Expr {
316 ExprKind::BoundedQuant(kind, rng, body).intern()
317 }
318
319 pub fn hole(kind: HoleKind) -> Expr {
320 ExprKind::Hole(kind).intern()
321 }
322
323 pub fn kvar(kvar: KVar) -> Expr {
324 ExprKind::KVar(kvar).intern()
325 }
326
327 pub fn alias(alias: AliasReft, args: List<Expr>) -> Expr {
328 ExprKind::Alias(alias, args).intern()
329 }
330
331 pub fn forall(expr: Binder<Expr>) -> Expr {
332 ExprKind::ForAll(expr).intern()
333 }
334
335 pub fn exists(expr: Binder<Expr>) -> Expr {
336 ExprKind::Exists(expr).intern()
337 }
338
339 pub fn binary_op(op: BinOp, e1: impl Into<Expr>, e2: impl Into<Expr>) -> Expr {
340 ExprKind::BinaryOp(op, e1.into(), e2.into()).intern()
341 }
342
343 pub fn prim_val(op: BinOp, e1: impl Into<Expr>, e2: impl Into<Expr>) -> Expr {
344 Expr::app(InternalFuncKind::Val(op), List::empty(), List::from_arr([e1.into(), e2.into()]))
345 }
346
347 pub fn prim_rel(op: BinOp, e1: impl Into<Expr>, e2: impl Into<Expr>) -> Expr {
348 Expr::app(InternalFuncKind::Rel(op), List::empty(), List::from_arr([e1.into(), e2.into()]))
349 }
350
351 pub fn unit_struct(def_id: DefId) -> Expr {
352 Expr::ctor_struct(def_id, List::empty())
353 }
354
355 pub fn cast(from: Sort, to: Sort, idx: Expr) -> Expr {
356 Expr::app(
357 InternalFuncKind::Cast,
358 List::from_arr([SortArg::Sort(from), SortArg::Sort(to)]),
359 List::from_arr([idx]),
360 )
361 }
362
363 pub fn app(func: impl Into<Expr>, sort_args: List<SortArg>, args: List<Expr>) -> Expr {
364 ExprKind::App(func.into(), sort_args, args).intern()
365 }
366
367 pub fn global_func(kind: SpecFuncKind) -> Expr {
368 ExprKind::GlobalFunc(kind).intern()
369 }
370
371 pub fn internal_func(kind: InternalFuncKind) -> Expr {
372 ExprKind::InternalFunc(kind).intern()
373 }
374
375 pub fn eq(e1: impl Into<Expr>, e2: impl Into<Expr>) -> Expr {
376 ExprKind::BinaryOp(BinOp::Eq, e1.into(), e2.into()).intern()
377 }
378
379 pub fn unary_op(op: UnOp, e: impl Into<Expr>) -> Expr {
380 ExprKind::UnaryOp(op, e.into()).intern()
381 }
382
383 pub fn ne(e1: impl Into<Expr>, e2: impl Into<Expr>) -> Expr {
384 ExprKind::BinaryOp(BinOp::Ne, e1.into(), e2.into()).intern()
385 }
386
387 pub fn ge(e1: impl Into<Expr>, e2: impl Into<Expr>) -> Expr {
388 ExprKind::BinaryOp(BinOp::Ge(Sort::Int), e1.into(), e2.into()).intern()
389 }
390
391 pub fn gt(e1: impl Into<Expr>, e2: impl Into<Expr>) -> Expr {
392 ExprKind::BinaryOp(BinOp::Gt(Sort::Int), e1.into(), e2.into()).intern()
393 }
394
395 pub fn lt(e1: impl Into<Expr>, e2: impl Into<Expr>) -> Expr {
396 ExprKind::BinaryOp(BinOp::Lt(Sort::Int), e1.into(), e2.into()).intern()
397 }
398
399 pub fn le(e1: impl Into<Expr>, e2: impl Into<Expr>) -> Expr {
400 ExprKind::BinaryOp(BinOp::Le(Sort::Int), e1.into(), e2.into()).intern()
401 }
402
403 pub fn implies(e1: impl Into<Expr>, e2: impl Into<Expr>) -> Expr {
404 ExprKind::BinaryOp(BinOp::Imp, e1.into(), e2.into()).intern()
405 }
406
407 pub fn field_proj(e: impl Into<Expr>, proj: FieldProj) -> Expr {
408 ExprKind::FieldProj(e.into(), proj).intern()
409 }
410
411 pub fn field_projs(e: impl Into<Expr>, projs: &[FieldProj]) -> Expr {
412 projs.iter().copied().fold(e.into(), Expr::field_proj)
413 }
414
415 pub fn path_proj(base: Expr, field: FieldIdx) -> Expr {
416 ExprKind::PathProj(base, field).intern()
417 }
418
419 pub fn not(&self) -> Expr {
420 ExprKind::UnaryOp(UnOp::Not, self.clone()).intern()
421 }
422
423 pub fn neg(&self) -> Expr {
424 ExprKind::UnaryOp(UnOp::Neg, self.clone()).intern()
425 }
426
427 pub fn kind(&self) -> &ExprKind {
428 &self.kind
429 }
430
431 pub fn is_atom(&self) -> bool {
434 !matches!(self.kind(), ExprKind::Abs(..) | ExprKind::BinaryOp(..) | ExprKind::ForAll(..))
435 }
436
437 pub fn is_trivially_true(&self) -> bool {
440 self.is_true()
441 || matches!(self.kind(), ExprKind::BinaryOp(BinOp::Eq | BinOp::Iff | BinOp::Imp, e1, e2) if e1.erase_spans() == e2.erase_spans())
442 }
443
444 pub fn is_trivially_false(&self) -> bool {
446 self.is_false()
447 }
448
449 fn is_true(&self) -> bool {
451 matches!(self.kind(), ExprKind::Constant(Constant::Bool(true)))
452 }
453
454 fn is_false(&self) -> bool {
456 matches!(self.kind(), ExprKind::Constant(Constant::Bool(false)))
457 }
458
459 pub fn from_const(tcx: TyCtxt, c: &Const) -> Expr {
460 match &c.kind {
461 ConstKind::Param(param_const) => Expr::const_generic(*param_const),
462 ConstKind::Value(ty, ValTree::Leaf(scalar)) => {
463 Expr::constant(Constant::from_scalar_int(tcx, *scalar, ty).unwrap())
464 }
465 ConstKind::Value(_ty, ValTree::Branch(_)) => {
466 bug!("todo: ValTree::Branch {c:?}")
467 }
468 ConstKind::Unevaluated(_) => bug!("unexpected `ConstKind::Unevaluated`"),
470
471 ConstKind::Infer(_) => bug!("unexpected `ConstKind::Infer`"),
472 }
473 }
474
475 fn const_op(op: &BinOp, c1: &Constant, c2: &Constant) -> Option<Constant> {
476 match op {
477 BinOp::Iff => c1.iff(c2),
478 BinOp::Imp => c1.imp(c2),
479 BinOp::Or => c1.or(c2),
480 BinOp::And => c1.and(c2),
481 BinOp::Gt(Sort::Int) => c1.gt(c2),
482 BinOp::Ge(Sort::Int) => c1.ge(c2),
483 BinOp::Lt(Sort::Int) => c2.gt(c1),
484 BinOp::Le(Sort::Int) => c2.ge(c1),
485 BinOp::Eq => Some(c1.eq(c2)),
486 BinOp::Ne => Some(c1.ne(c2)),
487 _ => None,
488 }
489 }
490
491 pub fn simplify(&self, assumed_preds: &SnapshotMap<Expr, ()>) -> Expr {
497 struct Simplify<'a> {
498 assumed_preds: &'a SnapshotMap<Expr, ()>,
499 }
500
501 impl TypeFolder for Simplify<'_> {
502 fn fold_expr(&mut self, expr: &Expr) -> Expr {
503 if self.assumed_preds.get(&expr.erase_spans()).is_some() {
504 return Expr::tt();
505 }
506 let span = expr.span();
507 match expr.kind() {
508 ExprKind::BinaryOp(op, e1, e2) => {
509 let e1 = e1.fold_with(self);
510 let e2 = e2.fold_with(self);
511 match (op, e1.kind(), e2.kind()) {
512 (BinOp::And, ExprKind::Constant(Constant::Bool(false)), _) => {
513 Expr::constant(Constant::Bool(false)).at_opt(e1.span())
514 }
515 (BinOp::And, _, ExprKind::Constant(Constant::Bool(false))) => {
516 Expr::constant(Constant::Bool(false)).at_opt(e2.span())
517 }
518 (BinOp::And, ExprKind::Constant(Constant::Bool(true)), _) => e2,
519 (BinOp::And, _, ExprKind::Constant(Constant::Bool(true))) => e1,
520 (op, ExprKind::Constant(c1), ExprKind::Constant(c2)) => {
521 if let Some(c) = Expr::const_op(op, c1, c2) {
522 Expr::constant(c).at_opt(span.or(e2.span()))
523 } else {
524 Expr::binary_op(op.clone(), e1, e2).at_opt(span)
525 }
526 }
527 _ => Expr::binary_op(op.clone(), e1, e2).at_opt(span),
528 }
529 }
530 ExprKind::UnaryOp(UnOp::Not, e) => {
531 let e = e.fold_with(self);
532 match e.kind() {
533 ExprKind::Constant(Constant::Bool(b)) => {
534 Expr::constant(Constant::Bool(!b))
535 }
536 ExprKind::UnaryOp(UnOp::Not, e) => e.clone(),
537 ExprKind::BinaryOp(BinOp::Eq, e1, e2) => {
538 Expr::binary_op(BinOp::Ne, e1, e2).at_opt(span)
539 }
540 _ => Expr::unary_op(UnOp::Not, e).at_opt(span),
541 }
542 }
543 ExprKind::IfThenElse(p, e1, e2) => {
544 let p = p.fold_with(self);
545 if p.is_trivially_true() {
546 e1.fold_with(self).at_opt(span)
547 } else if p.is_trivially_false() {
548 e2.fold_with(self).at_opt(span)
549 } else {
550 Expr::ite(p, e1.fold_with(self), e2.fold_with(self)).at_opt(span)
551 }
552 }
553 _ => expr.super_fold_with(self),
554 }
555 }
556 }
557 self.fold_with(&mut Simplify { assumed_preds })
558 }
559
560 pub fn to_loc(&self) -> Option<Loc> {
561 match self.kind() {
562 ExprKind::Local(local) => Some(Loc::Local(*local)),
563 ExprKind::Var(var) => Some(Loc::Var(*var)),
564 _ => None,
565 }
566 }
567
568 pub fn to_path(&self) -> Option<Path> {
569 let mut expr = self;
570 let mut proj = vec![];
571 while let ExprKind::PathProj(e, field) = expr.kind() {
572 proj.push(*field);
573 expr = e;
574 }
575 proj.reverse();
576 Some(Path::new(expr.to_loc()?, proj))
577 }
578
579 pub fn is_unit(&self) -> bool {
581 matches!(self.kind(), ExprKind::Tuple(flds) if flds.is_empty())
582 || matches!(self.kind(), ExprKind::Ctor(Ctor::Struct(_), flds) if flds.is_empty())
583 }
584
585 pub fn eta_expand_abs(&self, inputs: &BoundVariableKinds, output: Sort) -> Lambda {
586 let args = (0..inputs.len())
587 .map(|idx| Expr::bvar(INNERMOST, BoundVar::from_usize(idx), BoundReftKind::Anon))
588 .collect();
589 let body = Expr::app(self, List::empty(), args);
590 Lambda::bind_with_vars(body, inputs.clone(), output)
591 }
592
593 pub fn proj_and_reduce(&self, proj: FieldProj) -> Expr {
595 match self.kind() {
596 ExprKind::Tuple(flds) | ExprKind::Ctor(Ctor::Struct(_), flds) => {
597 flds[proj.field_idx() as usize].clone()
598 }
599 _ => Expr::field_proj(self.clone(), proj),
600 }
601 }
602
603 pub fn visit_conj<'a>(&'a self, mut f: impl FnMut(&'a Expr)) {
604 fn go<'a>(e: &'a Expr, f: &mut impl FnMut(&'a Expr)) {
605 if let ExprKind::BinaryOp(BinOp::And, e1, e2) = e.kind() {
606 go(e1, f);
607 go(e2, f);
608 } else {
609 f(e);
610 }
611 }
612 go(self, &mut f);
613 }
614
615 pub fn flatten_conjs(&self) -> Vec<&Expr> {
616 let mut vec = vec![];
617 self.visit_conj(|e| vec.push(e));
618 vec
619 }
620
621 pub fn has_evars(&self) -> bool {
622 struct HasEvars;
623
624 impl TypeVisitor for HasEvars {
625 type BreakTy = ();
626 fn visit_expr(&mut self, expr: &Expr) -> ControlFlow<Self::BreakTy> {
627 if let ExprKind::Var(Var::EVar(_)) = expr.kind() {
628 ControlFlow::Break(())
629 } else {
630 expr.super_visit_with(self)
631 }
632 }
633 }
634
635 self.visit_with(&mut HasEvars).is_break()
636 }
637
638 pub fn erase_spans(&self) -> Expr {
639 struct SpanEraser;
640 impl TypeFolder for SpanEraser {
641 fn fold_expr(&mut self, e: &Expr) -> Expr {
642 e.super_fold_with(self).at_opt(None)
643 }
644 }
645 self.fold_with(&mut SpanEraser)
646 }
647}
648
649#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Debug)]
650pub struct ESpan {
651 pub span: Span,
653 pub base: Option<Span>,
655}
656
657impl ESpan {
658 pub fn new(span: Span) -> Self {
659 Self { span, base: None }
660 }
661
662 pub fn with_base(&self, espan: ESpan) -> Self {
663 Self { span: self.span, base: Some(espan.span) }
664 }
665}
666
667#[derive(
668 Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Debug, TypeFoldable, TypeVisitable,
669)]
670pub enum BinOp {
671 Iff,
672 Imp,
673 Or,
674 And,
675 Eq,
676 Ne,
677 Gt(Sort),
678 Ge(Sort),
679 Lt(Sort),
680 Le(Sort),
681 Add(Sort),
682 Sub(Sort),
683 Mul(Sort),
684 Div(Sort),
685 Mod(Sort),
686 BitAnd(Sort),
687 BitOr(Sort),
688 BitXor(Sort),
689 BitShl(Sort),
690 BitShr(Sort),
691}
692
693#[derive(Clone, Copy, PartialEq, Eq, Hash, Encodable, Debug, Decodable)]
694pub enum UnOp {
695 Not,
696 Neg,
697}
698
699#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, TyEncodable, TyDecodable)]
700pub enum Ctor {
701 Struct(DefId),
703 Enum(DefId, VariantIdx),
705}
706
707impl Ctor {
708 pub fn def_id(&self) -> DefId {
709 match self {
710 Self::Struct(def_id) | Self::Enum(def_id, _) => *def_id,
711 }
712 }
713
714 pub fn variant_idx(&self) -> VariantIdx {
715 match self {
716 Self::Struct(_) => FIRST_VARIANT,
717 Self::Enum(_, variant_idx) => *variant_idx,
718 }
719 }
720
721 fn is_enum(&self) -> bool {
722 matches!(self, Self::Enum(..))
723 }
724}
725
726#[derive(Debug, Clone, TyEncodable, TyDecodable, PartialEq, Eq, Hash)]
740pub enum InternalFuncKind {
741 Val(BinOp),
743 Rel(BinOp),
745 Cast,
747}
748
749#[derive(Debug, Clone, TyEncodable, TyDecodable, PartialEq, Eq, Hash)]
750pub enum SpecFuncKind {
751 Thy(liquid_fixpoint::ThyFunc),
753 Uif(FluxDefId),
755 Def(FluxDefId),
757}
758
759#[derive(Clone, PartialEq, Eq, Hash, TyEncodable, Debug, TyDecodable)]
760pub enum ExprKind {
761 Var(Var),
762 Local(Local),
763 Constant(Constant),
764 ConstDefId(DefId),
766 BinaryOp(BinOp, Expr, Expr),
767 GlobalFunc(SpecFuncKind),
768 InternalFunc(InternalFuncKind),
769 UnaryOp(UnOp, Expr),
770 FieldProj(Expr, FieldProj),
771 Ctor(Ctor, List<Expr>),
773 Tuple(List<Expr>),
774 PathProj(Expr, FieldIdx),
775 IfThenElse(Expr, Expr, Expr),
776 KVar(KVar),
777 Alias(AliasReft, List<Expr>),
778 Let(Expr, Binder<Expr>),
779 App(Expr, List<SortArg>, List<Expr>),
785 Abs(Lambda),
795
796 BoundedQuant(fhir::QuantKind, fhir::Range, Binder<Expr>),
798 Hole(HoleKind),
812 ForAll(Binder<Expr>),
813 Exists(Binder<Expr>),
815 IsCtor(DefId, VariantIdx, Expr),
817}
818
819impl ExprKind {
820 fn intern(self) -> Expr {
821 Expr { kind: Interned::new(self), espan: None }
822 }
823}
824
825#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Debug)]
826pub enum AggregateKind {
827 Tuple(usize),
828 Adt(DefId),
829}
830
831#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Debug)]
832pub enum FieldProj {
833 Tuple { arity: usize, field: u32 },
834 Adt { def_id: DefId, field: u32 },
835}
836
837impl FieldProj {
838 pub fn arity(&self, genv: GlobalEnv) -> QueryResult<usize> {
839 match self {
840 FieldProj::Tuple { arity, .. } => Ok(*arity),
841 FieldProj::Adt { def_id, .. } => {
842 Ok(genv.adt_sort_def_of(*def_id)?.struct_variant().fields())
843 }
844 }
845 }
846
847 pub fn field_idx(&self) -> u32 {
848 match self {
849 FieldProj::Tuple { field, .. } | FieldProj::Adt { field, .. } => *field,
850 }
851 }
852}
853
854#[derive(
860 Debug, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, TypeFoldable, TypeVisitable,
861)]
862pub enum HoleKind {
863 Pred,
868 Expr(Sort),
875}
876
877#[derive(Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, TypeVisitable, TypeFoldable)]
882pub struct KVar {
883 pub kvid: KVid,
884 pub self_args: usize,
886 pub args: List<Expr>,
889}
890
891#[derive(Clone, Debug, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Encodable, Decodable)]
892pub struct EarlyReftParam {
893 pub index: u32,
894 pub name: Symbol,
895}
896
897#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Encodable, Decodable, Debug)]
898pub struct BoundReft {
899 pub var: BoundVar,
900 pub kind: BoundReftKind,
901}
902
903#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, TyEncodable, TyDecodable)]
904pub enum Var {
905 Free(Name),
906 Bound(DebruijnIndex, BoundReft),
907 EarlyParam(EarlyReftParam),
908 EVar(EVid),
909 ConstGeneric(ParamConst),
910}
911
912#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord, TyEncodable, TyDecodable)]
913pub struct Path {
914 pub loc: Loc,
915 projection: List<FieldIdx>,
916}
917
918#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, TyEncodable, TyDecodable)]
919pub enum Loc {
920 Local(Local),
921 Var(Var),
922}
923
924newtype_index! {
925 #[debug_format = "?{}e"]
927 #[orderable]
928 #[encodable]
929 pub struct EVid {}
930}
931
932newtype_index! {
933 #[debug_format = "$k{}"]
934 #[encodable]
935 pub struct KVid {}
936}
937
938newtype_index! {
939 #[debug_format = "a{}"]
940 #[orderable]
941 #[encodable]
942 pub struct Name {}
943}
944
945impl KVar {
946 pub fn new(kvid: KVid, self_args: usize, args: Vec<Expr>) -> Self {
947 KVar { kvid, self_args, args: List::from_vec(args) }
948 }
949
950 fn self_args(&self) -> &[Expr] {
951 &self.args[..self.self_args]
952 }
953
954 fn scope(&self) -> &[Expr] {
955 &self.args[self.self_args..]
956 }
957}
958
959impl Var {
960 pub fn to_expr(&self) -> Expr {
961 Expr::var(*self)
962 }
963}
964
965impl Path {
966 pub fn new(loc: Loc, projection: impl Into<List<FieldIdx>>) -> Path {
967 Path { loc, projection: projection.into() }
968 }
969
970 pub fn projection(&self) -> &[FieldIdx] {
971 &self.projection[..]
972 }
973
974 pub fn to_expr(&self) -> Expr {
975 self.projection
976 .iter()
977 .fold(self.loc.to_expr(), |e, f| Expr::path_proj(e, *f))
978 }
979
980 pub fn to_loc(&self) -> Option<Loc> {
981 if self.projection.is_empty() { Some(self.loc) } else { None }
982 }
983}
984
985impl Loc {
986 pub fn to_expr(&self) -> Expr {
987 match self {
988 Loc::Local(local) => Expr::local(*local),
989 Loc::Var(var) => Expr::var(*var),
990 }
991 }
992}
993
994macro_rules! impl_ops {
995 ($($op:ident: $method:ident),*) => {$(
996 impl<Rhs> std::ops::$op<Rhs> for Expr
997 where
998 Rhs: Into<Expr>,
999 {
1000 type Output = Expr;
1001
1002 fn $method(self, rhs: Rhs) -> Self::Output {
1003 let sort = crate::rty::Sort::Int;
1004 Expr::binary_op(BinOp::$op(sort), self, rhs)
1005 }
1006 }
1007
1008 impl<Rhs> std::ops::$op<Rhs> for &Expr
1009 where
1010 Rhs: Into<Expr>,
1011 {
1012 type Output = Expr;
1013
1014 fn $method(self, rhs: Rhs) -> Self::Output {
1015 let sort = crate::rty::Sort::Int;
1016 Expr::binary_op(BinOp::$op(sort), self, rhs)
1017 }
1018 }
1019 )*};
1020}
1021impl_ops!(Add: add, Sub: sub, Mul: mul, Div: div);
1022
1023impl From<i32> for Expr {
1024 fn from(value: i32) -> Self {
1025 Expr::constant(Constant::from(value))
1026 }
1027}
1028
1029impl From<&Expr> for Expr {
1030 fn from(e: &Expr) -> Self {
1031 e.clone()
1032 }
1033}
1034
1035impl From<Path> for Expr {
1036 fn from(path: Path) -> Self {
1037 path.to_expr()
1038 }
1039}
1040
1041impl From<Name> for Expr {
1042 fn from(name: Name) -> Self {
1043 Expr::fvar(name)
1044 }
1045}
1046
1047impl From<Var> for Expr {
1048 fn from(var: Var) -> Self {
1049 Expr::var(var)
1050 }
1051}
1052
1053impl From<SpecFuncKind> for Expr {
1054 fn from(kind: SpecFuncKind) -> Self {
1055 Expr::global_func(kind)
1056 }
1057}
1058
1059impl From<InternalFuncKind> for Expr {
1060 fn from(kind: InternalFuncKind) -> Self {
1061 Expr::internal_func(kind)
1062 }
1063}
1064
1065impl From<Loc> for Path {
1066 fn from(loc: Loc) -> Self {
1067 Path::new(loc, vec![])
1068 }
1069}
1070
1071impl From<Name> for Loc {
1072 fn from(name: Name) -> Self {
1073 Loc::Var(Var::Free(name))
1074 }
1075}
1076
1077impl From<Local> for Loc {
1078 fn from(local: Local) -> Self {
1079 Loc::Local(local)
1080 }
1081}
1082
1083#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Encodable, Decodable)]
1084pub struct Real(pub u128);
1085
1086#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Encodable, Decodable)]
1087pub enum Constant {
1088 Int(BigInt),
1089 Real(Real),
1090 Bool(bool),
1091 Str(Symbol),
1092 Char(char),
1093 BitVec(u128, u32),
1094}
1095
1096impl Constant {
1097 pub const ZERO: Constant = Constant::Int(BigInt::ZERO);
1098 pub const ONE: Constant = Constant::Int(BigInt::ONE);
1099 pub const TRUE: Constant = Constant::Bool(true);
1100
1101 fn to_bool(self) -> Option<bool> {
1102 match self {
1103 Constant::Bool(b) => Some(b),
1104 _ => None,
1105 }
1106 }
1107
1108 fn to_int(self) -> Option<BigInt> {
1109 match self {
1110 Constant::Int(n) => Some(n),
1111 _ => None,
1112 }
1113 }
1114
1115 pub fn iff(&self, other: &Constant) -> Option<Constant> {
1116 let b1 = self.to_bool()?;
1117 let b2 = other.to_bool()?;
1118 Some(Constant::Bool(b1 == b2))
1119 }
1120
1121 pub fn imp(&self, other: &Constant) -> Option<Constant> {
1122 let b1 = self.to_bool()?;
1123 let b2 = other.to_bool()?;
1124 Some(Constant::Bool(!b1 || b2))
1125 }
1126
1127 pub fn or(&self, other: &Constant) -> Option<Constant> {
1128 let b1 = self.to_bool()?;
1129 let b2 = other.to_bool()?;
1130 Some(Constant::Bool(b1 || b2))
1131 }
1132
1133 pub fn and(&self, other: &Constant) -> Option<Constant> {
1134 let b1 = self.to_bool()?;
1135 let b2 = other.to_bool()?;
1136 Some(Constant::Bool(b1 && b2))
1137 }
1138
1139 pub fn eq(&self, other: &Constant) -> Constant {
1140 Constant::Bool(*self == *other)
1141 }
1142
1143 pub fn ne(&self, other: &Constant) -> Constant {
1144 Constant::Bool(*self != *other)
1145 }
1146
1147 pub fn gt(&self, other: &Constant) -> Option<Constant> {
1148 let n1 = self.to_int()?;
1149 let n2 = other.to_int()?;
1150 Some(Constant::Bool(n1 > n2))
1151 }
1152
1153 pub fn ge(&self, other: &Constant) -> Option<Constant> {
1154 let n1 = self.to_int()?;
1155 let n2 = other.to_int()?;
1156 Some(Constant::Bool(n1 >= n2))
1157 }
1158
1159 pub fn from_scalar_int<'tcx, T>(tcx: TyCtxt<'tcx>, scalar: ScalarInt, t: &T) -> Option<Self>
1160 where
1161 T: ToRustc<'tcx, T = rustc_middle::ty::Ty<'tcx>>,
1162 {
1163 use rustc_middle::ty::TyKind;
1164 let ty = t.to_rustc(tcx);
1165 match ty.kind() {
1166 TyKind::Int(int_ty) => Some(Constant::from(scalar_to_int(tcx, scalar, *int_ty))),
1167 TyKind::Uint(uint_ty) => Some(Constant::from(scalar_to_uint(tcx, scalar, *uint_ty))),
1168 TyKind::Bool => {
1169 let b = scalar_to_bits(tcx, scalar, ty)?;
1170 Some(Constant::Bool(b != 0))
1171 }
1172 TyKind::Char => {
1173 let b = scalar_to_bits(tcx, scalar, ty)?;
1174 Some(Constant::Char(char::from_u32(b as u32)?))
1175 }
1176 _ => bug!(),
1177 }
1178 }
1179
1180 pub fn int_min(bit_width: u32) -> Constant {
1182 Constant::Int(BigInt::int_min(bit_width))
1183 }
1184
1185 pub fn int_max(bit_width: u32) -> Constant {
1187 Constant::Int(BigInt::int_max(bit_width))
1188 }
1189
1190 pub fn uint_max(bit_width: u32) -> Constant {
1192 Constant::Int(BigInt::uint_max(bit_width))
1193 }
1194}
1195
1196impl From<i32> for Constant {
1197 fn from(c: i32) -> Self {
1198 Constant::Int(c.into())
1199 }
1200}
1201
1202impl From<usize> for Constant {
1203 fn from(u: usize) -> Self {
1204 Constant::Int(u.into())
1205 }
1206}
1207
1208impl From<u32> for Constant {
1209 fn from(c: u32) -> Self {
1210 Constant::Int(c.into())
1211 }
1212}
1213
1214impl From<u128> for Constant {
1215 fn from(c: u128) -> Self {
1216 Constant::Int(c.into())
1217 }
1218}
1219
1220impl From<i128> for Constant {
1221 fn from(c: i128) -> Self {
1222 Constant::Int(c.into())
1223 }
1224}
1225
1226impl From<bool> for Constant {
1227 fn from(b: bool) -> Self {
1228 Constant::Bool(b)
1229 }
1230}
1231
1232impl From<Symbol> for Constant {
1233 fn from(s: Symbol) -> Self {
1234 Constant::Str(s)
1235 }
1236}
1237
1238impl From<char> for Constant {
1239 fn from(c: char) -> Self {
1240 Constant::Char(c)
1241 }
1242}
1243
1244impl_internable!(ExprKind);
1245impl_slice_internable!(Expr, KVar);
1246
1247#[derive(Debug)]
1248pub struct FieldBind<T> {
1249 pub name: Symbol,
1250 pub value: T,
1251}
1252
1253impl<T: Pretty> Pretty for FieldBind<T> {
1254 fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1255 w!(cx, f, "{}: {:?}", ^self.name, &self.value)
1256 }
1257}
1258
1259pub(crate) mod pretty {
1260 use flux_rustc_bridge::def_id_to_string;
1261
1262 use super::*;
1263 use crate::{name_of_thy_func, rty::pretty::nested_with_bound_vars};
1264
1265 #[derive(PartialEq, Eq, PartialOrd, Ord)]
1266 enum Precedence {
1267 Iff,
1268 Imp,
1269 Or,
1270 And,
1271 Cmp,
1272 Bitvec,
1273 AddSub,
1274 MulDiv,
1275 }
1276
1277 impl BinOp {
1278 fn precedence(&self) -> Precedence {
1279 match self {
1280 BinOp::Iff => Precedence::Iff,
1281 BinOp::Imp => Precedence::Imp,
1282 BinOp::Or => Precedence::Or,
1283 BinOp::And => Precedence::And,
1284 BinOp::Eq
1285 | BinOp::Ne
1286 | BinOp::Gt(_)
1287 | BinOp::Lt(_)
1288 | BinOp::Ge(_)
1289 | BinOp::Le(_) => Precedence::Cmp,
1290 BinOp::Add(_) | BinOp::Sub(_) => Precedence::AddSub,
1291 BinOp::Mul(_) | BinOp::Div(_) | BinOp::Mod(_) => Precedence::MulDiv,
1292 BinOp::BitAnd(_)
1293 | BinOp::BitOr(_)
1294 | BinOp::BitShl(_)
1295 | BinOp::BitShr(_)
1296 | BinOp::BitXor(_) => Precedence::Bitvec,
1297 }
1298 }
1299 }
1300
1301 impl Precedence {
1302 pub fn is_associative(&self) -> bool {
1303 !matches!(self, Precedence::Imp | Precedence::Cmp)
1304 }
1305 }
1306
1307 pub fn should_parenthesize(op: &BinOp, child: &Expr) -> bool {
1308 if let ExprKind::BinaryOp(child_op, ..) = child.kind() {
1309 child_op.precedence() < op.precedence()
1310 || (child_op.precedence() == op.precedence() && !op.precedence().is_associative())
1311 } else {
1312 false
1313 }
1314 }
1315
1316 impl Pretty for Ctor {
1317 fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1318 match self {
1319 Ctor::Struct(def_id) => {
1320 w!(cx, f, "{:?}", def_id)
1321 }
1322 Ctor::Enum(def_id, variant_idx) => {
1323 w!(cx, f, "{:?}::{:?}", def_id, ^variant_idx)
1324 }
1325 }
1326 }
1327 }
1328
1329 impl Pretty for fhir::QuantKind {
1330 fn fmt(&self, _cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1331 match self {
1332 fhir::QuantKind::Exists => w!(cx, f, "∃"),
1333 fhir::QuantKind::Forall => w!(cx, f, "∀"),
1334 }
1335 }
1336 }
1337
1338 impl Pretty for InternalFuncKind {
1339 fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1340 match self {
1341 InternalFuncKind::Val(op) => w!(cx, f, "[{:?}]", op),
1342 InternalFuncKind::Rel(op) => w!(cx, f, "[{:?}]?", op),
1343 InternalFuncKind::Cast => w!(cx, f, "cast"),
1344 }
1345 }
1346 }
1347
1348 impl Pretty for Expr {
1349 fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1350 let e = if cx.simplify_exprs {
1351 self.simplify(&SnapshotMap::default())
1352 } else {
1353 self.clone()
1354 };
1355 match e.kind() {
1356 ExprKind::Var(var) => w!(cx, f, "{:?}", var),
1357 ExprKind::Local(local) => w!(cx, f, "{:?}", ^local),
1358 ExprKind::ConstDefId(did) => w!(cx, f, "{}", ^def_id_to_string(*did)),
1359 ExprKind::Constant(c) => w!(cx, f, "{:?}", c),
1360
1361 ExprKind::BinaryOp(op, e1, e2) => {
1362 if should_parenthesize(op, e1) {
1363 w!(cx, f, "({:?})", e1)?;
1364 } else {
1365 w!(cx, f, "{:?}", e1)?;
1366 }
1367 if matches!(op, BinOp::Div(_)) {
1368 w!(cx, f, "{:?}", op)?;
1369 } else {
1370 w!(cx, f, " {:?} ", op)?;
1371 }
1372 if should_parenthesize(op, e2) {
1373 w!(cx, f, "({:?})", e2)?;
1374 } else {
1375 w!(cx, f, "{:?}", e2)?;
1376 }
1377 Ok(())
1378 }
1379 ExprKind::UnaryOp(op, e) => {
1380 if e.is_atom() {
1381 w!(cx, f, "{:?}{:?}", op, e)
1382 } else {
1383 w!(cx, f, "{:?}({:?})", op, e)
1384 }
1385 }
1386 ExprKind::FieldProj(e, proj) if let ExprKind::Ctor(_, _) = e.kind() => {
1387 w!(cx, f, "{:?}", e.proj_and_reduce(*proj))
1390 }
1391 ExprKind::FieldProj(e, proj) => {
1392 if e.is_atom() {
1393 w!(cx, f, "{:?}.{}", e, ^fmt_field_proj(cx, *proj))
1394 } else {
1395 w!(cx, f, "({:?}).{}", e, ^fmt_field_proj(cx, *proj))
1396 }
1397 }
1398 ExprKind::Tuple(flds) => {
1399 if let [e] = &flds[..] {
1400 w!(cx, f, "({:?},)", e)
1401 } else {
1402 w!(cx, f, "({:?})", join!(", ", flds))
1403 }
1404 }
1405 ExprKind::IsCtor(def_id, variant_idx, idx) => {
1406 w!(cx, f, "({:?} is {:?}::{:?})", idx, def_id, ^variant_idx)
1407 }
1408 ExprKind::Ctor(ctor, flds) => {
1409 let def_id = ctor.def_id();
1410 if let Some(adt_sort_def) = cx.adt_sort_def_of(def_id) {
1411 let variant = adt_sort_def.variant(ctor.variant_idx()).field_names();
1412 let fields = iter::zip(variant, flds)
1413 .map(|(name, value)| FieldBind { name: *name, value: value.clone() })
1414 .collect_vec();
1415 match ctor {
1416 Ctor::Struct(_) => {
1417 w!(cx, f, "{:?} {{ {:?} }}", def_id, join!(", ", fields))
1418 }
1419 Ctor::Enum(_, idx) => {
1420 if fields.is_empty() {
1421 w!(cx, f, "{:?}::{:?}", def_id, ^idx.index())
1422 } else {
1423 w!(cx, f, "{:?}::{:?}({:?})", def_id, ^idx.index(), join!(", ", fields))
1424 }
1425 }
1426 }
1427 } else {
1428 match ctor {
1429 Ctor::Struct(_) => {
1430 w!(cx, f, "{:?} {{ {:?} }}", def_id, join!(", ", flds))
1431 }
1432 Ctor::Enum(_, idx) => {
1433 w!(cx, f, "{:?}::{:?} {{ {:?} }}", def_id, ^idx, join!(", ", flds))
1434 }
1435 }
1436 }
1437 }
1438 ExprKind::PathProj(e, field) => {
1439 if e.is_atom() {
1440 w!(cx, f, "{:?}.{:?}", e, field)
1441 } else {
1442 w!(cx, f, "({:?}).{:?}", e, field)
1443 }
1444 }
1445 ExprKind::App(func, _, args) => {
1446 w!(cx, f, "{:?}({})",
1447 parens!(func, !func.is_atom()),
1448 ^args
1449 .iter()
1450 .format_with(", ", |arg, f| f(&format_args_cx!(cx, "{:?}", arg)))
1451 )
1452 }
1453 ExprKind::IfThenElse(p, e1, e2) => {
1454 w!(cx, f, "if {:?} {{ {:?} }} else {{ {:?} }}", p, e1, e2)
1455 }
1456 ExprKind::Hole(_) => {
1457 w!(cx, f, "*")
1458 }
1459 ExprKind::KVar(kvar) => {
1460 w!(cx, f, "{:?}", kvar)
1461 }
1462 ExprKind::Alias(alias, args) => {
1463 w!(cx, f, "{:?}({:?})", alias, join!(", ", args))
1464 }
1465 ExprKind::Abs(lam) => {
1466 w!(cx, f, "{:?}", lam)
1467 }
1468 ExprKind::GlobalFunc(SpecFuncKind::Def(did) | SpecFuncKind::Uif(did)) => {
1469 w!(cx, f, "{}", ^did.name())
1470 }
1471 ExprKind::GlobalFunc(SpecFuncKind::Thy(itf)) => {
1472 if let Some(name) = name_of_thy_func(*itf) {
1473 w!(cx, f, "{}", ^name)
1474 } else {
1475 w!(cx, f, "<error>")
1476 }
1477 }
1478 ExprKind::InternalFunc(func) => {
1479 w!(cx, f, "{:?}", func)
1480 }
1481 ExprKind::ForAll(expr) => {
1482 let vars = expr.vars();
1483 cx.with_bound_vars(vars, || {
1484 if !vars.is_empty() {
1485 cx.fmt_bound_vars(false, "∀", vars, ". ", f)?;
1486 }
1487 w!(cx, f, "{:?}", expr.skip_binder_ref())
1488 })
1489 }
1490 ExprKind::Exists(expr) => {
1491 let vars = expr.vars();
1492 cx.with_bound_vars(vars, || {
1493 if !vars.is_empty() {
1494 cx.fmt_bound_vars(false, "∃", vars, ". ", f)?;
1495 }
1496 w!(cx, f, "{:?}", expr.skip_binder_ref())
1497 })
1498 }
1499 ExprKind::BoundedQuant(kind, rng, body) => {
1500 let vars = body.vars();
1501 cx.with_bound_vars(vars, || {
1502 w!(
1503 cx,
1504 f,
1505 "{:?} {}..{} {{ {:?} }}",
1506 kind,
1507 ^rng.start,
1508 ^rng.end,
1509 body.skip_binder_ref()
1510 )
1511 })
1512 }
1513 ExprKind::Let(init, body) => {
1514 let vars = body.vars();
1515 cx.with_bound_vars(vars, || {
1516 cx.fmt_bound_vars(false, "(let ", vars, " = ", f)?;
1517 w!(cx, f, "{:?} in {:?})", init, body.skip_binder_ref())
1518 })
1519 }
1520 }
1521 }
1522 }
1523
1524 fn fmt_field_proj(cx: &PrettyCx, proj: FieldProj) -> String {
1525 if let FieldProj::Adt { def_id, field } = proj
1526 && let Some(adt_sort_def) = cx.adt_sort_def_of(def_id)
1527 {
1528 format!("{}", adt_sort_def.struct_variant().field_names()[field as usize])
1529 } else {
1530 format!("{}", proj.field_idx())
1531 }
1532 }
1533
1534 impl Pretty for Constant {
1535 fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1536 match self {
1537 Constant::Int(i) => w!(cx, f, "{i}"),
1538 Constant::BitVec(i, sz) => w!(cx, f, "bv({i}, {sz})"),
1539 Constant::Real(r) => w!(cx, f, "{}.0", ^r.0),
1540 Constant::Bool(b) => w!(cx, f, "{b}"),
1541 Constant::Str(sym) => w!(cx, f, "\"{sym}\""),
1542 Constant::Char(c) => w!(cx, f, "\'{c}\'"),
1543 }
1544 }
1545 }
1546
1547 impl Pretty for AliasReft {
1548 fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1549 w!(cx, f, "<({:?}) as {:?}", &self.args[0], self.assoc_id.parent())?;
1550 let args = &self.args[1..];
1551 if !args.is_empty() {
1552 w!(cx, f, "<{:?}>", join!(", ", args))?;
1553 }
1554 w!(cx, f, ">::{}", ^self.assoc_id.name())
1555 }
1556 }
1557
1558 impl Pretty for Lambda {
1559 fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1560 let vars = self.body.vars();
1561 cx.with_bound_vars(vars, || {
1564 cx.fmt_bound_vars(false, "λ", vars, ". ", f)?;
1565 w!(cx, f, "{:?}", self.body.as_ref().skip_binder())
1566 })
1567 }
1568 }
1569
1570 impl Pretty for Var {
1571 fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1572 match self {
1573 Var::Bound(debruijn, var) => cx.fmt_bound_reft(*debruijn, *var, f),
1574 Var::EarlyParam(var) => w!(cx, f, "{}", ^var.name),
1575 Var::Free(name) => w!(cx, f, "{:?}", ^name),
1576 Var::EVar(evar) => w!(cx, f, "{:?}", ^evar),
1577 Var::ConstGeneric(param) => w!(cx, f, "{}", ^param.name),
1578 }
1579 }
1580 }
1581
1582 impl Pretty for KVar {
1583 fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1584 w!(cx, f, "{:?}", ^self.kvid)?;
1585 match cx.kvar_args {
1586 KVarArgs::All => {
1587 w!(
1588 cx,
1589 f,
1590 "({:?})[{:?}]",
1591 join!(", ", self.self_args()),
1592 join!(", ", self.scope())
1593 )?;
1594 }
1595 KVarArgs::SelfOnly => w!(cx, f, "({:?})", join!(", ", self.self_args()))?,
1596 KVarArgs::Hide => {}
1597 }
1598 Ok(())
1599 }
1600 }
1601
1602 impl Pretty for Path {
1603 fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1604 w!(cx, f, "{:?}", &self.loc)?;
1605 for field in &self.projection {
1606 w!(cx, f, ".{}", ^u32::from(*field))?;
1607 }
1608 Ok(())
1609 }
1610 }
1611
1612 impl Pretty for Loc {
1613 fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1614 match self {
1615 Loc::Local(local) => w!(cx, f, "{:?}", ^local),
1616 Loc::Var(var) => w!(cx, f, "{:?}", var),
1617 }
1618 }
1619 }
1620
1621 impl Pretty for BinOp {
1622 fn fmt(&self, _cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1623 match self {
1624 BinOp::Iff => w!(cx, f, "⇔"),
1625 BinOp::Imp => w!(cx, f, "⇒"),
1626 BinOp::Or => w!(cx, f, "∨"),
1627 BinOp::And => w!(cx, f, "∧"),
1628 BinOp::Eq => w!(cx, f, "="),
1629 BinOp::Ne => w!(cx, f, "≠"),
1630 BinOp::Gt(_) => w!(cx, f, ">"),
1631 BinOp::Ge(_) => w!(cx, f, "≥"),
1632 BinOp::Lt(_) => w!(cx, f, "<"),
1633 BinOp::Le(_) => w!(cx, f, "≤"),
1634 BinOp::Add(_) => w!(cx, f, "+"),
1635 BinOp::Sub(_) => w!(cx, f, "-"),
1636 BinOp::Mul(_) => w!(cx, f, "*"),
1637 BinOp::Div(_) => w!(cx, f, "/"),
1638 BinOp::Mod(_) => w!(cx, f, "mod"),
1639 BinOp::BitAnd(_) => w!(cx, f, "&"),
1640 BinOp::BitOr(_) => w!(cx, f, "|"),
1641 BinOp::BitXor(_) => w!(cx, f, "^"),
1642 BinOp::BitShl(_) => w!(cx, f, "<<"),
1643 BinOp::BitShr(_) => w!(cx, f, ">>"),
1644 }
1645 }
1646 }
1647
1648 impl Pretty for UnOp {
1649 fn fmt(&self, _cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1650 match self {
1651 UnOp::Not => w!(cx, f, "¬"),
1652 UnOp::Neg => w!(cx, f, "-"),
1653 }
1654 }
1655 }
1656
1657 impl_debug_with_default_cx!(Expr, Loc, Path, Var, KVar, Lambda, AliasReft);
1658
1659 impl PrettyNested for Lambda {
1660 fn fmt_nested(&self, cx: &PrettyCx) -> Result<NestedString, fmt::Error> {
1661 nested_with_bound_vars(cx, "λ", self.body.vars(), None, |prefix| {
1663 let expr_d = self.body.skip_binder_ref().fmt_nested(cx)?;
1664 let text = format!("{}{}", prefix, expr_d.text);
1665 Ok(NestedString { text, children: expr_d.children, key: None })
1666 })
1667 }
1668 }
1669
1670 pub fn aggregate_nested(
1671 cx: &PrettyCx,
1672 ctor: &Ctor,
1673 flds: &[Expr],
1674 is_named: bool,
1675 ) -> Result<NestedString, fmt::Error> {
1676 let def_id = ctor.def_id();
1677 let mut text =
1678 if is_named && ctor.is_enum() { format_cx!(cx, "{:?}", ctor) } else { "".to_string() };
1679 if flds.is_empty() {
1680 Ok(NestedString { text, children: None, key: None })
1682 } else if flds.len() == 1 {
1683 text += &format_cx!(cx, "{:?}", flds[0].clone());
1685 Ok(NestedString { text, children: None, key: None })
1686 } else {
1687 let keys = if let Some(adt_sort_def) = cx.adt_sort_def_of(def_id) {
1688 adt_sort_def
1689 .variant(ctor.variant_idx())
1690 .field_names()
1691 .iter()
1692 .map(|name| format!("{name}"))
1693 .collect_vec()
1694 } else {
1695 (0..flds.len()).map(|i| format!("arg{i}")).collect_vec()
1696 };
1697 text += "{..}";
1699 let mut children = vec![];
1700 for (key, fld) in iter::zip(keys, flds) {
1701 let fld_d = fld.fmt_nested(cx)?;
1702 children.push(NestedString { key: Some(key), ..fld_d });
1703 }
1704 Ok(NestedString { text, children: Some(children), key: None })
1705 }
1706 }
1707
1708 impl PrettyNested for Expr {
1709 fn fmt_nested(&self, cx: &PrettyCx) -> Result<NestedString, fmt::Error> {
1710 let e = if cx.simplify_exprs {
1711 self.simplify(&SnapshotMap::default())
1712 } else {
1713 self.clone()
1714 };
1715 match e.kind() {
1716 ExprKind::Var(..)
1717 | ExprKind::Local(..)
1718 | ExprKind::Constant(..)
1719 | ExprKind::ConstDefId(..)
1720 | ExprKind::Hole(..)
1721 | ExprKind::GlobalFunc(..)
1722 | ExprKind::InternalFunc(..)
1723 | ExprKind::KVar(..) => debug_nested(cx, &e),
1724
1725 ExprKind::IfThenElse(p, e1, e2) => {
1726 let p_d = p.fmt_nested(cx)?;
1727 let e1_d = e1.fmt_nested(cx)?;
1728 let e2_d = e2.fmt_nested(cx)?;
1729 let text = format!("(if {} then {} else {})", p_d.text, e1_d.text, e2_d.text);
1730 let children = float_children(vec![p_d.children, e1_d.children, e2_d.children]);
1731 Ok(NestedString { text, children, key: None })
1732 }
1733 ExprKind::BinaryOp(op, e1, e2) => {
1734 let e1_d = e1.fmt_nested(cx)?;
1735 let e2_d = e2.fmt_nested(cx)?;
1736 let e1_text = if should_parenthesize(op, e1) {
1737 format!("({})", e1_d.text)
1738 } else {
1739 e1_d.text
1740 };
1741 let e2_text = if should_parenthesize(op, e2) {
1742 format!("({})", e2_d.text)
1743 } else {
1744 e2_d.text
1745 };
1746 let op_d = debug_nested(cx, op)?;
1747 let op_text = if matches!(op, BinOp::Div(_)) {
1748 op_d.text
1749 } else {
1750 format!(" {} ", op_d.text)
1751 };
1752 let text = format!("{e1_text}{op_text}{e2_text}");
1753 let children = float_children(vec![e1_d.children, e2_d.children]);
1754 Ok(NestedString { text, children, key: None })
1755 }
1756 ExprKind::UnaryOp(op, e) => {
1757 let e_d = e.fmt_nested(cx)?;
1758 let op_d = debug_nested(cx, op)?;
1759 let text = if e.is_atom() {
1760 format!("{}{}", op_d.text, e_d.text)
1761 } else {
1762 format!("{}({})", op_d.text, e_d.text)
1763 };
1764 Ok(NestedString { text, children: e_d.children, key: None })
1765 }
1766 ExprKind::FieldProj(e, proj) if let ExprKind::Ctor(_, _) = e.kind() => {
1767 e.proj_and_reduce(*proj).fmt_nested(cx)
1770 }
1771 ExprKind::FieldProj(e, proj) => {
1772 let e_d = e.fmt_nested(cx)?;
1773 let text = if e.is_atom() {
1774 format!("{}.{}", e_d.text, fmt_field_proj(cx, *proj))
1775 } else {
1776 format!("({}).{}", e_d.text, fmt_field_proj(cx, *proj))
1777 };
1778 Ok(NestedString { text, children: e_d.children, key: None })
1779 }
1780 ExprKind::Tuple(flds) => {
1781 let mut texts = vec![];
1782 let mut kidss = vec![];
1783 for e in flds {
1784 let e_d = e.fmt_nested(cx)?;
1785 texts.push(e_d.text);
1786 kidss.push(e_d.children);
1787 }
1788 let text = if let [e] = &texts[..] {
1789 format!("({e},)")
1790 } else {
1791 format!("({})", texts.join(", "))
1792 };
1793 let children = float_children(kidss);
1794 Ok(NestedString { text, children, key: None })
1795 }
1796 ExprKind::Ctor(ctor, flds) => aggregate_nested(cx, ctor, flds, true),
1797 ExprKind::IsCtor(def_id, variant_idx, idx) => {
1798 let text = format!("is::{:?}::{:?}( {:?} )", def_id, variant_idx, idx);
1799 Ok(NestedString { text, children: None, key: None })
1800 }
1801 ExprKind::PathProj(e, field) => {
1802 let e_d = e.fmt_nested(cx)?;
1803 let text = if e.is_atom() {
1804 format!("{}.{:?}", e_d.text, field)
1805 } else {
1806 format!("({}).{:?}", e_d.text, field)
1807 };
1808 Ok(NestedString { text, children: e_d.children, key: None })
1809 }
1810 ExprKind::Alias(alias, args) => {
1811 let mut texts = vec![];
1812 let mut kidss = vec![];
1813 for arg in args {
1814 let arg_d = arg.fmt_nested(cx)?;
1815 texts.push(arg_d.text);
1816 kidss.push(arg_d.children);
1817 }
1818 let text = format_cx!(cx, "{:?}({:?})", alias, texts.join(", "));
1819 let children = float_children(kidss);
1820 Ok(NestedString { text, children, key: None })
1821 }
1822 ExprKind::App(func, _, args) => {
1823 let func_d = func.fmt_nested(cx)?;
1824 let mut texts = vec![];
1825 let mut kidss = vec![func_d.children];
1826 for arg in args {
1827 let arg_d = arg.fmt_nested(cx)?;
1828 texts.push(arg_d.text);
1829 kidss.push(arg_d.children);
1830 }
1831 let text = if func.is_atom() {
1832 format!("{}({})", func_d.text, texts.join(", "))
1833 } else {
1834 format!("({})({})", func_d.text, texts.join(", "))
1835 };
1836 let children = float_children(kidss);
1837 Ok(NestedString { text, children, key: None })
1838 }
1839 ExprKind::Abs(lambda) => lambda.fmt_nested(cx),
1840 ExprKind::Let(init, body) => {
1841 nested_with_bound_vars(cx, "let", body.vars(), None, |prefix| {
1843 let body = body.skip_binder_ref().fmt_nested(cx)?;
1844 let text = format!("{:?} {}{}", init, prefix, body.text);
1845 Ok(NestedString { text, children: body.children, key: None })
1846 })
1847 }
1848 ExprKind::BoundedQuant(kind, rng, body) => {
1849 let left = match kind {
1850 fhir::QuantKind::Forall => "∀",
1851 fhir::QuantKind::Exists => "∃",
1852 };
1853 let right = Some(format!(" in {}..{}", rng.start, rng.end));
1854
1855 nested_with_bound_vars(cx, left, body.vars(), right, |all_str| {
1856 let expr_d = body.as_ref().skip_binder().fmt_nested(cx)?;
1857 let text = format!("{}{}", all_str, expr_d.text);
1858 Ok(NestedString { text, children: expr_d.children, key: None })
1859 })
1860 }
1861 ExprKind::ForAll(expr) => {
1862 nested_with_bound_vars(cx, "∀", expr.vars(), None, |all_str| {
1863 let expr_d = expr.as_ref().skip_binder().fmt_nested(cx)?;
1864 let text = format!("{}{}", all_str, expr_d.text);
1865 Ok(NestedString { text, children: expr_d.children, key: None })
1866 })
1867 }
1868 ExprKind::Exists(expr) => {
1869 nested_with_bound_vars(cx, "∀", expr.vars(), None, |all_str| {
1870 let expr_d = expr.as_ref().skip_binder().fmt_nested(cx)?;
1871 let text = format!("{}{}", all_str, expr_d.text);
1872 Ok(NestedString { text, children: expr_d.children, key: None })
1873 })
1874 }
1875 }
1876 }
1877 }
1878}