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