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