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 Name {
946 pub fn as_subscript(&self) -> String {
947 self.as_usize()
948 .to_string()
949 .chars()
950 .map(|c| {
951 match c {
952 '0' => '₀',
953 '1' => '₁',
954 '2' => '₂',
955 '3' => '₃',
956 '4' => '₄',
957 '5' => '₅',
958 '6' => '₆',
959 '7' => '₇',
960 '8' => '₈',
961 '9' => '₉',
962 _ => c,
963 }
964 })
965 .collect()
966 }
967}
968
969#[derive(Copy, Debug, Clone)]
970pub enum NameProvenance {
971 Unknown,
972 UnfoldBoundReft(BoundReftKind),
973}
974
975impl NameProvenance {
976 pub fn opt_symbol(&self) -> Option<Symbol> {
977 match &self {
978 NameProvenance::UnfoldBoundReft(BoundReftKind::Named(name)) => Some(*name),
979 _ => None,
980 }
981 }
982}
983
984impl KVar {
985 pub fn new(kvid: KVid, self_args: usize, args: Vec<Expr>) -> Self {
986 KVar { kvid, self_args, args: List::from_vec(args) }
987 }
988
989 fn self_args(&self) -> &[Expr] {
990 &self.args[..self.self_args]
991 }
992
993 fn scope(&self) -> &[Expr] {
994 &self.args[self.self_args..]
995 }
996}
997
998impl Var {
999 pub fn to_expr(&self) -> Expr {
1000 Expr::var(*self)
1001 }
1002}
1003
1004impl Path {
1005 pub fn new(loc: Loc, projection: impl Into<List<FieldIdx>>) -> Path {
1006 Path { loc, projection: projection.into() }
1007 }
1008
1009 pub fn projection(&self) -> &[FieldIdx] {
1010 &self.projection[..]
1011 }
1012
1013 pub fn to_expr(&self) -> Expr {
1014 self.projection
1015 .iter()
1016 .fold(self.loc.to_expr(), |e, f| Expr::path_proj(e, *f))
1017 }
1018
1019 pub fn to_loc(&self) -> Option<Loc> {
1020 if self.projection.is_empty() { Some(self.loc) } else { None }
1021 }
1022}
1023
1024impl Loc {
1025 pub fn to_expr(&self) -> Expr {
1026 match self {
1027 Loc::Local(local) => Expr::local(*local),
1028 Loc::Var(var) => Expr::var(*var),
1029 }
1030 }
1031}
1032
1033macro_rules! impl_ops {
1034 ($($op:ident: $method:ident),*) => {$(
1035 impl<Rhs> std::ops::$op<Rhs> for Expr
1036 where
1037 Rhs: Into<Expr>,
1038 {
1039 type Output = Expr;
1040
1041 fn $method(self, rhs: Rhs) -> Self::Output {
1042 let sort = crate::rty::Sort::Int;
1043 Expr::binary_op(BinOp::$op(sort), self, rhs)
1044 }
1045 }
1046
1047 impl<Rhs> std::ops::$op<Rhs> for &Expr
1048 where
1049 Rhs: Into<Expr>,
1050 {
1051 type Output = Expr;
1052
1053 fn $method(self, rhs: Rhs) -> Self::Output {
1054 let sort = crate::rty::Sort::Int;
1055 Expr::binary_op(BinOp::$op(sort), self, rhs)
1056 }
1057 }
1058 )*};
1059}
1060impl_ops!(Add: add, Sub: sub, Mul: mul, Div: div);
1061
1062impl From<i32> for Expr {
1063 fn from(value: i32) -> Self {
1064 Expr::constant(Constant::from(value))
1065 }
1066}
1067
1068impl From<&Expr> for Expr {
1069 fn from(e: &Expr) -> Self {
1070 e.clone()
1071 }
1072}
1073
1074impl From<Path> for Expr {
1075 fn from(path: Path) -> Self {
1076 path.to_expr()
1077 }
1078}
1079
1080impl From<Name> for Expr {
1081 fn from(name: Name) -> Self {
1082 Expr::fvar(name)
1083 }
1084}
1085
1086impl From<Var> for Expr {
1087 fn from(var: Var) -> Self {
1088 Expr::var(var)
1089 }
1090}
1091
1092impl From<SpecFuncKind> for Expr {
1093 fn from(kind: SpecFuncKind) -> Self {
1094 Expr::global_func(kind)
1095 }
1096}
1097
1098impl From<InternalFuncKind> for Expr {
1099 fn from(kind: InternalFuncKind) -> Self {
1100 Expr::internal_func(kind)
1101 }
1102}
1103
1104impl From<Loc> for Path {
1105 fn from(loc: Loc) -> Self {
1106 Path::new(loc, vec![])
1107 }
1108}
1109
1110impl From<Name> for Loc {
1111 fn from(name: Name) -> Self {
1112 Loc::Var(Var::Free(name))
1113 }
1114}
1115
1116impl From<Local> for Loc {
1117 fn from(local: Local) -> Self {
1118 Loc::Local(local)
1119 }
1120}
1121
1122#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Encodable, Decodable)]
1123pub struct Real(pub u128);
1124
1125#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Encodable, Decodable)]
1126pub enum Constant {
1127 Int(BigInt),
1128 Real(Real),
1129 Bool(bool),
1130 Str(Symbol),
1131 Char(char),
1132 BitVec(u128, u32),
1133}
1134
1135impl Constant {
1136 pub const ZERO: Constant = Constant::Int(BigInt::ZERO);
1137 pub const ONE: Constant = Constant::Int(BigInt::ONE);
1138 pub const TRUE: Constant = Constant::Bool(true);
1139
1140 fn to_bool(self) -> Option<bool> {
1141 match self {
1142 Constant::Bool(b) => Some(b),
1143 _ => None,
1144 }
1145 }
1146
1147 fn to_int(self) -> Option<BigInt> {
1148 match self {
1149 Constant::Int(n) => Some(n),
1150 _ => None,
1151 }
1152 }
1153
1154 pub fn iff(&self, other: &Constant) -> Option<Constant> {
1155 let b1 = self.to_bool()?;
1156 let b2 = other.to_bool()?;
1157 Some(Constant::Bool(b1 == b2))
1158 }
1159
1160 pub fn imp(&self, other: &Constant) -> Option<Constant> {
1161 let b1 = self.to_bool()?;
1162 let b2 = other.to_bool()?;
1163 Some(Constant::Bool(!b1 || b2))
1164 }
1165
1166 pub fn or(&self, other: &Constant) -> Option<Constant> {
1167 let b1 = self.to_bool()?;
1168 let b2 = other.to_bool()?;
1169 Some(Constant::Bool(b1 || b2))
1170 }
1171
1172 pub fn and(&self, other: &Constant) -> Option<Constant> {
1173 let b1 = self.to_bool()?;
1174 let b2 = other.to_bool()?;
1175 Some(Constant::Bool(b1 && b2))
1176 }
1177
1178 pub fn eq(&self, other: &Constant) -> Constant {
1179 Constant::Bool(*self == *other)
1180 }
1181
1182 pub fn ne(&self, other: &Constant) -> Constant {
1183 Constant::Bool(*self != *other)
1184 }
1185
1186 pub fn gt(&self, other: &Constant) -> Option<Constant> {
1187 let n1 = self.to_int()?;
1188 let n2 = other.to_int()?;
1189 Some(Constant::Bool(n1 > n2))
1190 }
1191
1192 pub fn ge(&self, other: &Constant) -> Option<Constant> {
1193 let n1 = self.to_int()?;
1194 let n2 = other.to_int()?;
1195 Some(Constant::Bool(n1 >= n2))
1196 }
1197
1198 pub fn from_scalar_int<'tcx, T>(tcx: TyCtxt<'tcx>, scalar: ScalarInt, t: &T) -> Option<Self>
1199 where
1200 T: ToRustc<'tcx, T = rustc_middle::ty::Ty<'tcx>>,
1201 {
1202 use rustc_middle::ty::TyKind;
1203 let ty = t.to_rustc(tcx);
1204 match ty.kind() {
1205 TyKind::Int(int_ty) => Some(Constant::from(scalar_to_int(tcx, scalar, *int_ty))),
1206 TyKind::Uint(uint_ty) => Some(Constant::from(scalar_to_uint(tcx, scalar, *uint_ty))),
1207 TyKind::Bool => {
1208 let b = scalar_to_bits(tcx, scalar, ty)?;
1209 Some(Constant::Bool(b != 0))
1210 }
1211 TyKind::Char => {
1212 let b = scalar_to_bits(tcx, scalar, ty)?;
1213 Some(Constant::Char(char::from_u32(b as u32)?))
1214 }
1215 _ => bug!(),
1216 }
1217 }
1218
1219 pub fn int_min(bit_width: u32) -> Constant {
1221 Constant::Int(BigInt::int_min(bit_width))
1222 }
1223
1224 pub fn int_max(bit_width: u32) -> Constant {
1226 Constant::Int(BigInt::int_max(bit_width))
1227 }
1228
1229 pub fn uint_max(bit_width: u32) -> Constant {
1231 Constant::Int(BigInt::uint_max(bit_width))
1232 }
1233}
1234
1235impl From<i32> for Constant {
1236 fn from(c: i32) -> Self {
1237 Constant::Int(c.into())
1238 }
1239}
1240
1241impl From<usize> for Constant {
1242 fn from(u: usize) -> Self {
1243 Constant::Int(u.into())
1244 }
1245}
1246
1247impl From<u32> for Constant {
1248 fn from(c: u32) -> Self {
1249 Constant::Int(c.into())
1250 }
1251}
1252
1253impl From<u64> for Constant {
1254 fn from(c: u64) -> Self {
1255 Constant::Int(c.into())
1256 }
1257}
1258
1259impl From<u128> for Constant {
1260 fn from(c: u128) -> Self {
1261 Constant::Int(c.into())
1262 }
1263}
1264
1265impl From<i128> for Constant {
1266 fn from(c: i128) -> Self {
1267 Constant::Int(c.into())
1268 }
1269}
1270
1271impl From<bool> for Constant {
1272 fn from(b: bool) -> Self {
1273 Constant::Bool(b)
1274 }
1275}
1276
1277impl From<Symbol> for Constant {
1278 fn from(s: Symbol) -> Self {
1279 Constant::Str(s)
1280 }
1281}
1282
1283impl From<char> for Constant {
1284 fn from(c: char) -> Self {
1285 Constant::Char(c)
1286 }
1287}
1288
1289impl_internable!(ExprKind);
1290impl_slice_internable!(Expr, KVar);
1291
1292#[derive(Debug)]
1293pub struct FieldBind<T> {
1294 pub name: Symbol,
1295 pub value: T,
1296}
1297
1298impl<T: Pretty> Pretty for FieldBind<T> {
1299 fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1300 w!(cx, f, "{}: {:?}", ^self.name, &self.value)
1301 }
1302}
1303
1304pub(crate) mod pretty {
1305
1306 use flux_rustc_bridge::def_id_to_string;
1307
1308 use super::*;
1309 use crate::name_of_thy_func;
1310
1311 #[derive(PartialEq, Eq, PartialOrd, Ord)]
1312 enum Precedence {
1313 Iff,
1314 Imp,
1315 Or,
1316 And,
1317 Cmp,
1318 Bitvec,
1319 AddSub,
1320 MulDiv,
1321 }
1322
1323 impl BinOp {
1324 fn precedence(&self) -> Precedence {
1325 match self {
1326 BinOp::Iff => Precedence::Iff,
1327 BinOp::Imp => Precedence::Imp,
1328 BinOp::Or => Precedence::Or,
1329 BinOp::And => Precedence::And,
1330 BinOp::Eq
1331 | BinOp::Ne
1332 | BinOp::Gt(_)
1333 | BinOp::Lt(_)
1334 | BinOp::Ge(_)
1335 | BinOp::Le(_) => Precedence::Cmp,
1336 BinOp::Add(_) | BinOp::Sub(_) => Precedence::AddSub,
1337 BinOp::Mul(_) | BinOp::Div(_) | BinOp::Mod(_) => Precedence::MulDiv,
1338 BinOp::BitAnd(_)
1339 | BinOp::BitOr(_)
1340 | BinOp::BitShl(_)
1341 | BinOp::BitShr(_)
1342 | BinOp::BitXor(_) => Precedence::Bitvec,
1343 }
1344 }
1345 }
1346
1347 impl Precedence {
1348 pub fn is_associative(&self) -> bool {
1349 !matches!(self, Precedence::Imp | Precedence::Cmp)
1350 }
1351 }
1352
1353 pub fn should_parenthesize(op: &BinOp, child: &Expr) -> bool {
1354 if let ExprKind::BinaryOp(child_op, ..) = child.kind() {
1355 child_op.precedence() < op.precedence()
1356 || (child_op.precedence() == op.precedence() && !op.precedence().is_associative())
1357 } else {
1358 false
1359 }
1360 }
1361
1362 impl Pretty for Ctor {
1363 fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1364 match self {
1365 Ctor::Struct(def_id) => {
1366 w!(cx, f, "{:?}", def_id)
1367 }
1368 Ctor::Enum(def_id, variant_idx) => {
1369 w!(cx, f, "{:?}::{:?}", def_id, ^variant_idx)
1370 }
1371 }
1372 }
1373 }
1374
1375 impl Pretty for fhir::QuantKind {
1376 fn fmt(&self, _cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1377 match self {
1378 fhir::QuantKind::Exists => w!(cx, f, "∃"),
1379 fhir::QuantKind::Forall => w!(cx, f, "∀"),
1380 }
1381 }
1382 }
1383
1384 impl Pretty for InternalFuncKind {
1385 fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1386 match self {
1387 InternalFuncKind::Val(op) => w!(cx, f, "[{:?}]", op),
1388 InternalFuncKind::Rel(op) => w!(cx, f, "[{:?}]?", op),
1389 InternalFuncKind::Cast => w!(cx, f, "cast"),
1390 }
1391 }
1392 }
1393
1394 impl Pretty for Expr {
1395 fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1396 let e = if cx.simplify_exprs {
1397 self.simplify(&SnapshotMap::default())
1398 } else {
1399 self.clone()
1400 };
1401 match e.kind() {
1402 ExprKind::Var(var) => w!(cx, f, "{:?}", var),
1403 ExprKind::Local(local) => w!(cx, f, "{:?}", ^local),
1404 ExprKind::ConstDefId(did) => w!(cx, f, "{}", ^def_id_to_string(*did)),
1405 ExprKind::Constant(c) => w!(cx, f, "{:?}", c),
1406
1407 ExprKind::BinaryOp(op, e1, e2) => {
1408 if should_parenthesize(op, e1) {
1409 w!(cx, f, "({:?})", e1)?;
1410 } else {
1411 w!(cx, f, "{:?}", e1)?;
1412 }
1413 if matches!(op, BinOp::Div(_)) {
1414 w!(cx, f, "{:?}", op)?;
1415 } else {
1416 w!(cx, f, " {:?} ", op)?;
1417 }
1418 if should_parenthesize(op, e2) {
1419 w!(cx, f, "({:?})", e2)?;
1420 } else {
1421 w!(cx, f, "{:?}", e2)?;
1422 }
1423 Ok(())
1424 }
1425 ExprKind::UnaryOp(op, e) => {
1426 if e.is_atom() {
1427 w!(cx, f, "{:?}{:?}", op, e)
1428 } else {
1429 w!(cx, f, "{:?}({:?})", op, e)
1430 }
1431 }
1432 ExprKind::FieldProj(e, proj) if let ExprKind::Ctor(_, _) = e.kind() => {
1433 w!(cx, f, "{:?}", e.proj_and_reduce(*proj))
1436 }
1437 ExprKind::FieldProj(e, proj) => {
1438 if e.is_atom() {
1439 w!(cx, f, "{:?}.{}", e, ^fmt_field_proj(cx, *proj))
1440 } else {
1441 w!(cx, f, "({:?}).{}", e, ^fmt_field_proj(cx, *proj))
1442 }
1443 }
1444 ExprKind::Tuple(flds) => {
1445 if let [e] = &flds[..] {
1446 w!(cx, f, "({:?},)", e)
1447 } else {
1448 w!(cx, f, "({:?})", join!(", ", flds))
1449 }
1450 }
1451 ExprKind::IsCtor(def_id, variant_idx, idx) => {
1452 w!(cx, f, "({:?} is {:?}::{:?})", idx, def_id, ^variant_idx)
1453 }
1454 ExprKind::Ctor(ctor, flds) => {
1455 let def_id = ctor.def_id();
1456 if let Some(adt_sort_def) = cx.adt_sort_def_of(def_id) {
1457 let variant = adt_sort_def.variant(ctor.variant_idx()).field_names();
1458 let fields = iter::zip(variant, flds)
1459 .map(|(name, value)| FieldBind { name: *name, value: value.clone() })
1460 .collect_vec();
1461 match ctor {
1462 Ctor::Struct(_) => {
1463 w!(cx, f, "{:?} {{ {:?} }}", def_id, join!(", ", fields))
1464 }
1465 Ctor::Enum(_, idx) => {
1466 if fields.is_empty() {
1467 w!(cx, f, "{:?}::{:?}", def_id, ^idx.index())
1468 } else {
1469 w!(cx, f, "{:?}::{:?}({:?})", def_id, ^idx.index(), join!(", ", fields))
1470 }
1471 }
1472 }
1473 } else {
1474 match ctor {
1475 Ctor::Struct(_) => {
1476 w!(cx, f, "{:?} {{ {:?} }}", def_id, join!(", ", flds))
1477 }
1478 Ctor::Enum(_, idx) => {
1479 w!(cx, f, "{:?}::{:?} {{ {:?} }}", def_id, ^idx, join!(", ", flds))
1480 }
1481 }
1482 }
1483 }
1484 ExprKind::PathProj(e, field) => {
1485 if e.is_atom() {
1486 w!(cx, f, "{:?}.{:?}", e, field)
1487 } else {
1488 w!(cx, f, "({:?}).{:?}", e, field)
1489 }
1490 }
1491 ExprKind::App(func, _, args) => {
1492 w!(cx, f, "{:?}({})",
1493 parens!(func, !func.is_atom()),
1494 ^args
1495 .iter()
1496 .format_with(", ", |arg, f| f(&format_args_cx!(cx, "{:?}", arg)))
1497 )
1498 }
1499 ExprKind::IfThenElse(p, e1, e2) => {
1500 w!(cx, f, "if {:?} {{ {:?} }} else {{ {:?} }}", p, e1, e2)
1501 }
1502 ExprKind::Hole(_) => {
1503 w!(cx, f, "*")
1504 }
1505 ExprKind::KVar(kvar) => {
1506 w!(cx, f, "{:?}", kvar)
1507 }
1508 ExprKind::Alias(alias, args) => {
1509 w!(cx, f, "{:?}({:?})", alias, join!(", ", args))
1510 }
1511 ExprKind::Abs(lam) => {
1512 w!(cx, f, "{:?}", lam)
1513 }
1514 ExprKind::GlobalFunc(SpecFuncKind::Def(did) | SpecFuncKind::Uif(did)) => {
1515 w!(cx, f, "{}", ^did.name())
1516 }
1517 ExprKind::GlobalFunc(SpecFuncKind::Thy(itf)) => {
1518 if let Some(name) = name_of_thy_func(*itf) {
1519 w!(cx, f, "{}", ^name)
1520 } else {
1521 w!(cx, f, "<error>")
1522 }
1523 }
1524 ExprKind::InternalFunc(func) => {
1525 w!(cx, f, "{:?}", func)
1526 }
1527 ExprKind::ForAll(expr) => {
1528 let vars = expr.vars();
1529 cx.with_bound_vars(vars, || {
1530 if !vars.is_empty() {
1531 cx.fmt_bound_vars(false, "∀", vars, ". ", f)?;
1532 }
1533 w!(cx, f, "{:?}", expr.skip_binder_ref())
1534 })
1535 }
1536 ExprKind::Exists(expr) => {
1537 let vars = expr.vars();
1538 cx.with_bound_vars(vars, || {
1539 if !vars.is_empty() {
1540 cx.fmt_bound_vars(false, "∃", vars, ". ", f)?;
1541 }
1542 w!(cx, f, "{:?}", expr.skip_binder_ref())
1543 })
1544 }
1545 ExprKind::BoundedQuant(kind, rng, body) => {
1546 let vars = body.vars();
1547 cx.with_bound_vars(vars, || {
1548 w!(
1549 cx,
1550 f,
1551 "{:?} {}..{} {{ {:?} }}",
1552 kind,
1553 ^rng.start,
1554 ^rng.end,
1555 body.skip_binder_ref()
1556 )
1557 })
1558 }
1559 ExprKind::Let(init, body) => {
1560 let vars = body.vars();
1561 cx.with_bound_vars(vars, || {
1562 cx.fmt_bound_vars(false, "(let ", vars, " = ", f)?;
1563 w!(cx, f, "{:?} in {:?})", init, body.skip_binder_ref())
1564 })
1565 }
1566 }
1567 }
1568 }
1569
1570 fn fmt_field_proj(cx: &PrettyCx, proj: FieldProj) -> String {
1571 if let FieldProj::Adt { def_id, field } = proj
1572 && let Some(adt_sort_def) = cx.adt_sort_def_of(def_id)
1573 {
1574 format!("{}", adt_sort_def.struct_variant().field_names()[field as usize])
1575 } else {
1576 format!("{}", proj.field_idx())
1577 }
1578 }
1579
1580 impl Pretty for Constant {
1581 fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1582 match self {
1583 Constant::Int(i) => w!(cx, f, "{i}"),
1584 Constant::BitVec(i, sz) => w!(cx, f, "bv({i}, {sz})"),
1585 Constant::Real(r) => w!(cx, f, "{}.0", ^r.0),
1586 Constant::Bool(b) => w!(cx, f, "{b}"),
1587 Constant::Str(sym) => w!(cx, f, "\"{sym}\""),
1588 Constant::Char(c) => w!(cx, f, "\'{c}\'"),
1589 }
1590 }
1591 }
1592
1593 impl Pretty for AliasReft {
1594 fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1595 w!(cx, f, "<({:?}) as {:?}", &self.args[0], self.assoc_id.parent())?;
1596 let args = &self.args[1..];
1597 if !args.is_empty() {
1598 w!(cx, f, "<{:?}>", join!(", ", args))?;
1599 }
1600 w!(cx, f, ">::{}", ^self.assoc_id.name())
1601 }
1602 }
1603
1604 impl Pretty for Lambda {
1605 fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1606 let vars = self.body.vars();
1607 cx.with_bound_vars(vars, || {
1610 cx.fmt_bound_vars(false, "λ", vars, ". ", f)?;
1611 w!(cx, f, "{:?}", self.body.as_ref().skip_binder())
1612 })
1613 }
1614 }
1615
1616 impl Pretty for Var {
1617 fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1618 match self {
1619 Var::Bound(debruijn, var) => cx.fmt_bound_reft(*debruijn, *var, f),
1620 Var::EarlyParam(var) => w!(cx, f, "{}", ^var.name),
1621 Var::Free(name) => w!(cx, f, "{:?}", ^name),
1622 Var::EVar(evar) => w!(cx, f, "{:?}", ^evar),
1623 Var::ConstGeneric(param) => w!(cx, f, "{}", ^param.name),
1624 }
1625 }
1626 }
1627
1628 impl Pretty for KVar {
1629 fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1630 w!(cx, f, "{:?}", ^self.kvid)?;
1631 match cx.kvar_args {
1632 KVarArgs::All => {
1633 w!(
1634 cx,
1635 f,
1636 "({:?})[{:?}]",
1637 join!(", ", self.self_args()),
1638 join!(", ", self.scope())
1639 )?;
1640 }
1641 KVarArgs::SelfOnly => w!(cx, f, "({:?})", join!(", ", self.self_args()))?,
1642 KVarArgs::Hide => {}
1643 }
1644 Ok(())
1645 }
1646 }
1647
1648 impl Pretty for Path {
1649 fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1650 w!(cx, f, "{:?}", &self.loc)?;
1651 for field in &self.projection {
1652 w!(cx, f, ".{}", ^u32::from(*field))?;
1653 }
1654 Ok(())
1655 }
1656 }
1657
1658 impl Pretty for Loc {
1659 fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1660 match self {
1661 Loc::Local(local) => w!(cx, f, "{:?}", ^local),
1662 Loc::Var(var) => w!(cx, f, "{:?}", var),
1663 }
1664 }
1665 }
1666
1667 impl Pretty for BinOp {
1668 fn fmt(&self, _cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1669 match self {
1670 BinOp::Iff => w!(cx, f, "⇔"),
1671 BinOp::Imp => w!(cx, f, "⇒"),
1672 BinOp::Or => w!(cx, f, "∨"),
1673 BinOp::And => w!(cx, f, "∧"),
1674 BinOp::Eq => w!(cx, f, "="),
1675 BinOp::Ne => w!(cx, f, "≠"),
1676 BinOp::Gt(_) => w!(cx, f, ">"),
1677 BinOp::Ge(_) => w!(cx, f, "≥"),
1678 BinOp::Lt(_) => w!(cx, f, "<"),
1679 BinOp::Le(_) => w!(cx, f, "≤"),
1680 BinOp::Add(_) => w!(cx, f, "+"),
1681 BinOp::Sub(_) => w!(cx, f, "-"),
1682 BinOp::Mul(_) => w!(cx, f, "*"),
1683 BinOp::Div(_) => w!(cx, f, "/"),
1684 BinOp::Mod(_) => w!(cx, f, "mod"),
1685 BinOp::BitAnd(_) => w!(cx, f, "&"),
1686 BinOp::BitOr(_) => w!(cx, f, "|"),
1687 BinOp::BitXor(_) => w!(cx, f, "^"),
1688 BinOp::BitShl(_) => w!(cx, f, "<<"),
1689 BinOp::BitShr(_) => w!(cx, f, ">>"),
1690 }
1691 }
1692 }
1693
1694 impl Pretty for UnOp {
1695 fn fmt(&self, _cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1696 match self {
1697 UnOp::Not => w!(cx, f, "¬"),
1698 UnOp::Neg => w!(cx, f, "-"),
1699 }
1700 }
1701 }
1702
1703 impl_debug_with_default_cx!(Expr, Loc, Path, Var, KVar, Lambda, AliasReft);
1704
1705 impl PrettyNested for Lambda {
1706 fn fmt_nested(&self, cx: &PrettyCx) -> Result<NestedString, fmt::Error> {
1707 cx.nested_with_bound_vars("λ", self.body.vars(), None, |prefix| {
1709 let expr_d = self.body.skip_binder_ref().fmt_nested(cx)?;
1710 let text = format!("{}{}", prefix, expr_d.text);
1711 Ok(NestedString { text, children: expr_d.children, key: None })
1712 })
1713 }
1714 }
1715
1716 pub fn aggregate_nested(
1717 cx: &PrettyCx,
1718 ctor: &Ctor,
1719 flds: &[Expr],
1720 is_named: bool,
1721 ) -> Result<NestedString, fmt::Error> {
1722 let def_id = ctor.def_id();
1723 let mut text =
1724 if is_named && ctor.is_enum() { format_cx!(cx, "{:?}", ctor) } else { "".to_string() };
1725 if flds.is_empty() {
1726 Ok(NestedString { text, children: None, key: None })
1728 } else if flds.len() == 1 {
1729 text += &flds[0].fmt_nested(cx)?.text;
1731 Ok(NestedString { text, children: None, key: None })
1732 } else {
1733 let keys = if let Some(adt_sort_def) = cx.adt_sort_def_of(def_id) {
1734 adt_sort_def
1735 .variant(ctor.variant_idx())
1736 .field_names()
1737 .iter()
1738 .map(|name| format!("{name}"))
1739 .collect_vec()
1740 } else {
1741 (0..flds.len()).map(|i| format!("arg{i}")).collect_vec()
1742 };
1743 text += "{..}";
1745 let mut children = vec![];
1746 for (key, fld) in iter::zip(keys, flds) {
1747 let fld_d = fld.fmt_nested(cx)?;
1748 children.push(NestedString { key: Some(key), ..fld_d });
1749 }
1750 Ok(NestedString { text, children: Some(children), key: None })
1751 }
1752 }
1753
1754 impl PrettyNested for Name {
1755 fn fmt_nested(&self, cx: &PrettyCx) -> Result<NestedString, fmt::Error> {
1756 let text = cx.fmt_name(self);
1757 Ok(NestedString { text, key: None, children: None })
1758 }
1759 }
1760
1761 impl PrettyNested for Expr {
1762 fn fmt_nested(&self, cx: &PrettyCx) -> Result<NestedString, fmt::Error> {
1763 let e = if cx.simplify_exprs {
1764 self.simplify(&SnapshotMap::default())
1765 } else {
1766 self.clone()
1767 };
1768 match e.kind() {
1769 ExprKind::Var(Var::Free(name)) => name.fmt_nested(cx),
1770 ExprKind::Var(..)
1771 | ExprKind::Local(..)
1772 | ExprKind::Constant(..)
1773 | ExprKind::ConstDefId(..)
1774 | ExprKind::Hole(..)
1775 | ExprKind::GlobalFunc(..)
1776 | ExprKind::InternalFunc(..) => debug_nested(cx, &e),
1777 ExprKind::KVar(kvar) => {
1778 let kv = format!("{:?}", kvar.kvid);
1779 let mut strs = vec![kv];
1780 for arg in &kvar.args {
1781 strs.push(arg.fmt_nested(cx)?.text);
1782 }
1783 let text = format!("##[{}]##", strs.join("##"));
1784 Ok(NestedString { text, children: None, key: None })
1785 }
1786 ExprKind::IfThenElse(p, e1, e2) => {
1787 let p_d = p.fmt_nested(cx)?;
1788 let e1_d = e1.fmt_nested(cx)?;
1789 let e2_d = e2.fmt_nested(cx)?;
1790 let text = format!("(if {} then {} else {})", p_d.text, e1_d.text, e2_d.text);
1791 let children = float_children(vec![p_d.children, e1_d.children, e2_d.children]);
1792 Ok(NestedString { text, children, key: None })
1793 }
1794 ExprKind::BinaryOp(op, e1, e2) => {
1795 let e1_d = e1.fmt_nested(cx)?;
1796 let e2_d = e2.fmt_nested(cx)?;
1797 let e1_text = if should_parenthesize(op, e1) {
1798 format!("({})", e1_d.text)
1799 } else {
1800 e1_d.text
1801 };
1802 let e2_text = if should_parenthesize(op, e2) {
1803 format!("({})", e2_d.text)
1804 } else {
1805 e2_d.text
1806 };
1807 let op_d = debug_nested(cx, op)?;
1808 let op_text = if matches!(op, BinOp::Div(_)) {
1809 op_d.text
1810 } else {
1811 format!(" {} ", op_d.text)
1812 };
1813 let text = format!("{e1_text}{op_text}{e2_text}");
1814 let children = float_children(vec![e1_d.children, e2_d.children]);
1815 Ok(NestedString { text, children, key: None })
1816 }
1817 ExprKind::UnaryOp(op, e) => {
1818 let e_d = e.fmt_nested(cx)?;
1819 let op_d = debug_nested(cx, op)?;
1820 let text = if e.is_atom() {
1821 format!("{}{}", op_d.text, e_d.text)
1822 } else {
1823 format!("{}({})", op_d.text, e_d.text)
1824 };
1825 Ok(NestedString { text, children: e_d.children, key: None })
1826 }
1827 ExprKind::FieldProj(e, proj) if let ExprKind::Ctor(_, _) = e.kind() => {
1828 e.proj_and_reduce(*proj).fmt_nested(cx)
1831 }
1832 ExprKind::FieldProj(e, proj) => {
1833 let e_d = e.fmt_nested(cx)?;
1834 let text = if e.is_atom() {
1835 format!("{}.{}", e_d.text, fmt_field_proj(cx, *proj))
1836 } else {
1837 format!("({}).{}", e_d.text, fmt_field_proj(cx, *proj))
1838 };
1839 Ok(NestedString { text, children: e_d.children, key: None })
1840 }
1841 ExprKind::Tuple(flds) => {
1842 let mut texts = vec![];
1843 let mut kidss = vec![];
1844 for e in flds {
1845 let e_d = e.fmt_nested(cx)?;
1846 texts.push(e_d.text);
1847 kidss.push(e_d.children);
1848 }
1849 let text = if let [e] = &texts[..] {
1850 format!("({e},)")
1851 } else {
1852 format!("({})", texts.join(", "))
1853 };
1854 let children = float_children(kidss);
1855 Ok(NestedString { text, children, key: None })
1856 }
1857 ExprKind::Ctor(ctor, flds) => aggregate_nested(cx, ctor, flds, true),
1858 ExprKind::IsCtor(def_id, variant_idx, idx) => {
1859 let text = format!("is::{:?}::{:?}( {:?} )", def_id, variant_idx, idx);
1860 Ok(NestedString { text, children: None, key: None })
1861 }
1862 ExprKind::PathProj(e, field) => {
1863 let e_d = e.fmt_nested(cx)?;
1864 let text = if e.is_atom() {
1865 format!("{}.{:?}", e_d.text, field)
1866 } else {
1867 format!("({}).{:?}", e_d.text, field)
1868 };
1869 Ok(NestedString { text, children: e_d.children, key: None })
1870 }
1871 ExprKind::Alias(alias, args) => {
1872 let mut texts = vec![];
1873 let mut kidss = vec![];
1874 for arg in args {
1875 let arg_d = arg.fmt_nested(cx)?;
1876 texts.push(arg_d.text);
1877 kidss.push(arg_d.children);
1878 }
1879 let text = format_cx!(cx, "{:?}({:?})", alias, texts.join(", "));
1880 let children = float_children(kidss);
1881 Ok(NestedString { text, children, key: None })
1882 }
1883 ExprKind::App(func, _, args) => {
1884 let func_d = func.fmt_nested(cx)?;
1885 let mut texts = vec![];
1886 let mut kidss = vec![func_d.children];
1887 for arg in args {
1888 let arg_d = arg.fmt_nested(cx)?;
1889 texts.push(arg_d.text);
1890 kidss.push(arg_d.children);
1891 }
1892 let text = if func.is_atom() {
1893 format!("{}({})", func_d.text, texts.join(", "))
1894 } else {
1895 format!("({})({})", func_d.text, texts.join(", "))
1896 };
1897 let children = float_children(kidss);
1898 Ok(NestedString { text, children, key: None })
1899 }
1900 ExprKind::Abs(lambda) => lambda.fmt_nested(cx),
1901 ExprKind::Let(init, body) => {
1902 cx.nested_with_bound_vars("let", body.vars(), None, |prefix| {
1904 let body = body.skip_binder_ref().fmt_nested(cx)?;
1905 let text = format!("{:?} {}{}", init, prefix, body.text);
1906 Ok(NestedString { text, children: body.children, key: None })
1907 })
1908 }
1909 ExprKind::BoundedQuant(kind, rng, body) => {
1910 let left = match kind {
1911 fhir::QuantKind::Forall => "∀",
1912 fhir::QuantKind::Exists => "∃",
1913 };
1914 let right = Some(format!(" in {}..{}", rng.start, rng.end));
1915
1916 cx.nested_with_bound_vars(left, body.vars(), right, |all_str| {
1917 let expr_d = body.as_ref().skip_binder().fmt_nested(cx)?;
1918 let text = format!("{}{}", all_str, expr_d.text);
1919 Ok(NestedString { text, children: expr_d.children, key: None })
1920 })
1921 }
1922 ExprKind::ForAll(expr) => {
1923 cx.nested_with_bound_vars("∀", expr.vars(), None, |all_str| {
1924 let expr_d = expr.as_ref().skip_binder().fmt_nested(cx)?;
1925 let text = format!("{}{}", all_str, expr_d.text);
1926 Ok(NestedString { text, children: expr_d.children, key: None })
1927 })
1928 }
1929 ExprKind::Exists(expr) => {
1930 cx.nested_with_bound_vars("∀", expr.vars(), None, |all_str| {
1931 let expr_d = expr.as_ref().skip_binder().fmt_nested(cx)?;
1932 let text = format!("{}{}", all_str, expr_d.text);
1933 Ok(NestedString { text, children: expr_d.children, key: None })
1934 })
1935 }
1936 }
1937 }
1938 }
1939}