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