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