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, SpecFuncKind},
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 unit_struct(def_id: DefId) -> Expr {
312 Expr::ctor_struct(def_id, List::empty())
313 }
314
315 pub fn app(func: impl Into<Expr>, args: List<Expr>) -> Expr {
316 ExprKind::App(func.into(), args).intern()
317 }
318
319 pub fn global_func(kind: SpecFuncKind) -> Expr {
320 ExprKind::GlobalFunc(kind).intern()
321 }
322
323 pub fn eq(e1: impl Into<Expr>, e2: impl Into<Expr>) -> Expr {
324 ExprKind::BinaryOp(BinOp::Eq, e1.into(), e2.into()).intern()
325 }
326
327 pub fn unary_op(op: UnOp, e: impl Into<Expr>) -> Expr {
328 ExprKind::UnaryOp(op, e.into()).intern()
329 }
330
331 pub fn ne(e1: impl Into<Expr>, e2: impl Into<Expr>) -> Expr {
332 ExprKind::BinaryOp(BinOp::Ne, e1.into(), e2.into()).intern()
333 }
334
335 pub fn ge(e1: impl Into<Expr>, e2: impl Into<Expr>) -> Expr {
336 ExprKind::BinaryOp(BinOp::Ge(Sort::Int), e1.into(), e2.into()).intern()
337 }
338
339 pub fn gt(e1: impl Into<Expr>, e2: impl Into<Expr>) -> Expr {
340 ExprKind::BinaryOp(BinOp::Gt(Sort::Int), e1.into(), e2.into()).intern()
341 }
342
343 pub fn lt(e1: impl Into<Expr>, e2: impl Into<Expr>) -> Expr {
344 ExprKind::BinaryOp(BinOp::Lt(Sort::Int), e1.into(), e2.into()).intern()
345 }
346
347 pub fn le(e1: impl Into<Expr>, e2: impl Into<Expr>) -> Expr {
348 ExprKind::BinaryOp(BinOp::Le(Sort::Int), e1.into(), e2.into()).intern()
349 }
350
351 pub fn implies(e1: impl Into<Expr>, e2: impl Into<Expr>) -> Expr {
352 ExprKind::BinaryOp(BinOp::Imp, e1.into(), e2.into()).intern()
353 }
354
355 pub fn field_proj(e: impl Into<Expr>, proj: FieldProj) -> Expr {
356 ExprKind::FieldProj(e.into(), proj).intern()
357 }
358
359 pub fn field_projs(e: impl Into<Expr>, projs: &[FieldProj]) -> Expr {
360 projs.iter().copied().fold(e.into(), Expr::field_proj)
361 }
362
363 pub fn path_proj(base: Expr, field: FieldIdx) -> Expr {
364 ExprKind::PathProj(base, field).intern()
365 }
366
367 pub fn not(&self) -> Expr {
368 ExprKind::UnaryOp(UnOp::Not, self.clone()).intern()
369 }
370
371 pub fn neg(&self) -> Expr {
372 ExprKind::UnaryOp(UnOp::Neg, self.clone()).intern()
373 }
374
375 pub fn kind(&self) -> &ExprKind {
376 &self.kind
377 }
378
379 pub fn is_atom(&self) -> bool {
382 !matches!(self.kind(), ExprKind::Abs(..) | ExprKind::BinaryOp(..) | ExprKind::ForAll(..))
383 }
384
385 pub fn is_trivially_true(&self) -> bool {
388 self.is_true()
389 || matches!(self.kind(), ExprKind::BinaryOp(BinOp::Eq | BinOp::Iff | BinOp::Imp, e1, e2) if e1.erase_spans() == e2.erase_spans())
390 }
391
392 pub fn is_trivially_false(&self) -> bool {
394 self.is_false()
395 }
396
397 fn is_true(&self) -> bool {
399 matches!(self.kind(), ExprKind::Constant(Constant::Bool(true)))
400 }
401
402 fn is_false(&self) -> bool {
404 matches!(self.kind(), ExprKind::Constant(Constant::Bool(false)))
405 }
406
407 pub fn from_const(tcx: TyCtxt, c: &Const) -> Expr {
408 match &c.kind {
409 ConstKind::Param(param_const) => Expr::const_generic(*param_const),
410 ConstKind::Value(ty, ValTree::Leaf(scalar)) => {
411 Expr::constant(Constant::from_scalar_int(tcx, *scalar, ty).unwrap())
412 }
413 ConstKind::Value(_ty, ValTree::Branch(_)) => {
414 bug!("todo: ValTree::Branch {c:?}")
415 }
416 ConstKind::Unevaluated(_) => bug!("unexpected `ConstKind::Unevaluated`"),
418
419 ConstKind::Infer(_) => bug!("unexpected `ConstKind::Infer`"),
420 }
421 }
422
423 pub fn is_binary_op(&self) -> bool {
424 matches!(self.kind(), ExprKind::BinaryOp(..))
425 }
426
427 fn const_op(op: &BinOp, c1: &Constant, c2: &Constant) -> Option<Constant> {
428 match op {
429 BinOp::Iff => c1.iff(c2),
430 BinOp::Imp => c1.imp(c2),
431 BinOp::Or => c1.or(c2),
432 BinOp::And => c1.and(c2),
433 BinOp::Gt(Sort::Int) => c1.gt(c2),
434 BinOp::Ge(Sort::Int) => c1.ge(c2),
435 BinOp::Lt(Sort::Int) => c2.gt(c1),
436 BinOp::Le(Sort::Int) => c2.ge(c1),
437 BinOp::Eq => Some(c1.eq(c2)),
438 BinOp::Ne => Some(c1.ne(c2)),
439 _ => None,
440 }
441 }
442
443 pub fn simplify(&self, assumed_preds: &SnapshotMap<Expr, ()>) -> Expr {
449 struct Simplify<'a> {
450 assumed_preds: &'a SnapshotMap<Expr, ()>,
451 }
452
453 impl TypeFolder for Simplify<'_> {
454 fn fold_expr(&mut self, expr: &Expr) -> Expr {
455 if self.assumed_preds.get(&expr.erase_spans()).is_some() {
456 return Expr::tt();
457 }
458 let span = expr.span();
459 match expr.kind() {
460 ExprKind::BinaryOp(op, e1, e2) => {
461 let e1 = e1.fold_with(self);
462 let e2 = e2.fold_with(self);
463 match (op, e1.kind(), e2.kind()) {
464 (BinOp::And, ExprKind::Constant(Constant::Bool(false)), _) => {
465 Expr::constant(Constant::Bool(false)).at_opt(e1.span())
466 }
467 (BinOp::And, _, ExprKind::Constant(Constant::Bool(false))) => {
468 Expr::constant(Constant::Bool(false)).at_opt(e2.span())
469 }
470 (BinOp::And, ExprKind::Constant(Constant::Bool(true)), _) => e2,
471 (BinOp::And, _, ExprKind::Constant(Constant::Bool(true))) => e1,
472 (op, ExprKind::Constant(c1), ExprKind::Constant(c2)) => {
473 if let Some(c) = Expr::const_op(op, c1, c2) {
474 Expr::constant(c).at_opt(span.or(e2.span()))
475 } else {
476 Expr::binary_op(op.clone(), e1, e2).at_opt(span)
477 }
478 }
479 _ => Expr::binary_op(op.clone(), e1, e2).at_opt(span),
480 }
481 }
482 ExprKind::UnaryOp(UnOp::Not, e) => {
483 let e = e.fold_with(self);
484 match e.kind() {
485 ExprKind::Constant(Constant::Bool(b)) => {
486 Expr::constant(Constant::Bool(!b))
487 }
488 ExprKind::UnaryOp(UnOp::Not, e) => e.clone(),
489 ExprKind::BinaryOp(BinOp::Eq, e1, e2) => {
490 Expr::binary_op(BinOp::Ne, e1, e2).at_opt(span)
491 }
492 _ => Expr::unary_op(UnOp::Not, e).at_opt(span),
493 }
494 }
495 ExprKind::IfThenElse(p, e1, e2) => {
496 let p = p.fold_with(self);
497 if p.is_trivially_true() {
498 e1.fold_with(self).at_opt(span)
499 } else if p.is_trivially_false() {
500 e2.fold_with(self).at_opt(span)
501 } else {
502 Expr::ite(p, e1.fold_with(self), e2.fold_with(self)).at_opt(span)
503 }
504 }
505 _ => expr.super_fold_with(self),
506 }
507 }
508 }
509 self.fold_with(&mut Simplify { assumed_preds })
510 }
511
512 pub fn to_loc(&self) -> Option<Loc> {
513 match self.kind() {
514 ExprKind::Local(local) => Some(Loc::Local(*local)),
515 ExprKind::Var(var) => Some(Loc::Var(*var)),
516 _ => None,
517 }
518 }
519
520 pub fn to_path(&self) -> Option<Path> {
521 let mut expr = self;
522 let mut proj = vec![];
523 while let ExprKind::PathProj(e, field) = expr.kind() {
524 proj.push(*field);
525 expr = e;
526 }
527 proj.reverse();
528 Some(Path::new(expr.to_loc()?, proj))
529 }
530
531 pub fn is_abs(&self) -> bool {
532 matches!(self.kind(), ExprKind::Abs(..))
533 }
534
535 pub fn is_unit(&self) -> bool {
537 matches!(self.kind(), ExprKind::Tuple(flds) if flds.is_empty())
538 || matches!(self.kind(), ExprKind::Ctor(Ctor::Struct(_), flds) if flds.is_empty())
539 }
540
541 pub fn eta_expand_abs(&self, inputs: &BoundVariableKinds, output: Sort) -> Lambda {
542 let args = (0..inputs.len())
543 .map(|idx| Expr::bvar(INNERMOST, BoundVar::from_usize(idx), BoundReftKind::Annon))
544 .collect();
545 let body = Expr::app(self, args);
546 Lambda::bind_with_vars(body, inputs.clone(), output)
547 }
548
549 pub fn proj_and_reduce(&self, proj: FieldProj) -> Expr {
551 match self.kind() {
552 ExprKind::Tuple(flds) | ExprKind::Ctor(Ctor::Struct(_), flds) => {
553 flds[proj.field_idx() as usize].clone()
554 }
555 _ => Expr::field_proj(self.clone(), proj),
556 }
557 }
558
559 pub fn flatten_conjs(&self) -> Vec<&Expr> {
560 fn go<'a>(e: &'a Expr, vec: &mut Vec<&'a Expr>) {
561 if let ExprKind::BinaryOp(BinOp::And, e1, e2) = e.kind() {
562 go(e1, vec);
563 go(e2, vec);
564 } else {
565 vec.push(e);
566 }
567 }
568 let mut vec = vec![];
569 go(self, &mut vec);
570 vec
571 }
572
573 pub fn has_evars(&self) -> bool {
574 struct HasEvars;
575
576 impl TypeVisitor for HasEvars {
577 type BreakTy = ();
578 fn visit_expr(&mut self, expr: &Expr) -> ControlFlow<Self::BreakTy> {
579 if let ExprKind::Var(Var::EVar(_)) = expr.kind() {
580 ControlFlow::Break(())
581 } else {
582 expr.super_visit_with(self)
583 }
584 }
585 }
586
587 self.visit_with(&mut HasEvars).is_break()
588 }
589
590 pub fn erase_spans(&self) -> Expr {
591 struct SpanEraser;
592 impl TypeFolder for SpanEraser {
593 fn fold_expr(&mut self, e: &Expr) -> Expr {
594 e.super_fold_with(self).at_opt(None)
595 }
596 }
597 self.fold_with(&mut SpanEraser)
598 }
599}
600
601#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Debug)]
602pub struct ESpan {
603 pub span: Span,
605 pub base: Option<Span>,
607}
608
609impl ESpan {
610 pub fn new(span: Span) -> Self {
611 Self { span, base: None }
612 }
613
614 pub fn with_base(&self, espan: ESpan) -> Self {
615 Self { span: self.span, base: Some(espan.span) }
616 }
617}
618
619#[derive(
620 Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Debug, TypeFoldable, TypeVisitable,
621)]
622pub enum BinOp {
623 Iff,
624 Imp,
625 Or,
626 And,
627 Eq,
628 Ne,
629 Gt(Sort),
630 Ge(Sort),
631 Lt(Sort),
632 Le(Sort),
633 Add(Sort),
634 Sub(Sort),
635 Mul(Sort),
636 Div(Sort),
637 Mod(Sort),
638 BitAnd,
639 BitOr,
640 BitShl,
641 BitShr,
642}
643
644#[derive(Clone, Copy, PartialEq, Eq, Hash, Encodable, Debug, Decodable)]
645pub enum UnOp {
646 Not,
647 Neg,
648}
649
650#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, TyEncodable, TyDecodable)]
651pub enum Ctor {
652 Struct(DefId),
654 Enum(DefId, VariantIdx),
656}
657
658impl Ctor {
659 pub fn def_id(&self) -> DefId {
660 match self {
661 Self::Struct(def_id) | Self::Enum(def_id, _) => *def_id,
662 }
663 }
664
665 pub fn variant_idx(&self) -> VariantIdx {
666 match self {
667 Self::Struct(_) => FIRST_VARIANT,
668 Self::Enum(_, variant_idx) => *variant_idx,
669 }
670 }
671
672 fn is_enum(&self) -> bool {
673 matches!(self, Self::Enum(..))
674 }
675}
676
677#[derive(Clone, PartialEq, Eq, Hash, TyEncodable, Debug, TyDecodable)]
678pub enum ExprKind {
679 Var(Var),
680 Local(Local),
681 Constant(Constant),
682 ConstDefId(DefId),
683 BinaryOp(BinOp, Expr, Expr),
684 GlobalFunc(SpecFuncKind),
685 UnaryOp(UnOp, Expr),
686 FieldProj(Expr, FieldProj),
687 Ctor(Ctor, List<Expr>),
689 Tuple(List<Expr>),
690 PathProj(Expr, FieldIdx),
691 IfThenElse(Expr, Expr, Expr),
692 KVar(KVar),
693 Alias(AliasReft, List<Expr>),
694 Let(Expr, Binder<Expr>),
695 App(Expr, List<Expr>),
701 Abs(Lambda),
711
712 BoundedQuant(fhir::QuantKind, fhir::Range, Binder<Expr>),
714 Hole(HoleKind),
728 ForAll(Binder<Expr>),
729}
730
731impl ExprKind {
732 fn intern(self) -> Expr {
733 Expr { kind: Interned::new(self), espan: None }
734 }
735}
736
737#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Debug)]
738pub enum AggregateKind {
739 Tuple(usize),
740 Adt(DefId),
741}
742
743impl AggregateKind {
744 pub fn to_proj(self, field: u32) -> FieldProj {
745 match self {
746 AggregateKind::Tuple(arity) => FieldProj::Tuple { arity, field },
747 AggregateKind::Adt(def_id) => FieldProj::Adt { def_id, field },
748 }
749 }
750}
751
752#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Debug)]
753pub enum FieldProj {
754 Tuple { arity: usize, field: u32 },
755 Adt { def_id: DefId, field: u32 },
756}
757
758impl FieldProj {
759 pub fn arity(&self, genv: GlobalEnv) -> QueryResult<usize> {
760 match self {
761 FieldProj::Tuple { arity, .. } => Ok(*arity),
762 FieldProj::Adt { def_id, .. } => {
763 Ok(genv.adt_sort_def_of(*def_id)?.struct_variant().fields())
764 }
765 }
766 }
767
768 pub fn field_idx(&self) -> u32 {
769 match self {
770 FieldProj::Tuple { field, .. } | FieldProj::Adt { field, .. } => *field,
771 }
772 }
773}
774
775#[derive(
781 Debug, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, TypeFoldable, TypeVisitable,
782)]
783pub enum HoleKind {
784 Pred,
789 Expr(Sort),
796}
797
798#[derive(Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, TypeVisitable, TypeFoldable)]
803pub struct KVar {
804 pub kvid: KVid,
805 pub self_args: usize,
807 pub args: List<Expr>,
810}
811
812#[derive(Clone, Debug, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Encodable, Decodable)]
813pub struct EarlyReftParam {
814 pub index: u32,
815 pub name: Symbol,
816}
817
818#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Encodable, Decodable, Debug)]
819pub struct BoundReft {
820 pub var: BoundVar,
821 pub kind: BoundReftKind,
822}
823
824#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, TyEncodable, TyDecodable)]
825pub enum Var {
826 Free(Name),
827 Bound(DebruijnIndex, BoundReft),
828 EarlyParam(EarlyReftParam),
829 EVar(EVid),
830 ConstGeneric(ParamConst),
831}
832
833#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord, TyEncodable, TyDecodable)]
834pub struct Path {
835 pub loc: Loc,
836 projection: List<FieldIdx>,
837}
838
839#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, TyEncodable, TyDecodable)]
840pub enum Loc {
841 Local(Local),
842 Var(Var),
843}
844
845newtype_index! {
846 #[debug_format = "?{}e"]
848 #[orderable]
849 #[encodable]
850 pub struct EVid {}
851}
852
853newtype_index! {
854 #[debug_format = "$k{}"]
855 #[encodable]
856 pub struct KVid {}
857}
858
859newtype_index! {
860 #[debug_format = "a{}"]
861 #[orderable]
862 #[encodable]
863 pub struct Name {}
864}
865
866impl KVar {
867 pub fn new(kvid: KVid, self_args: usize, args: Vec<Expr>) -> Self {
868 KVar { kvid, self_args, args: List::from_vec(args) }
869 }
870
871 fn self_args(&self) -> &[Expr] {
872 &self.args[..self.self_args]
873 }
874
875 fn scope(&self) -> &[Expr] {
876 &self.args[self.self_args..]
877 }
878}
879
880impl Var {
881 pub fn to_expr(&self) -> Expr {
882 Expr::var(*self)
883 }
884}
885
886impl Path {
887 pub fn new(loc: Loc, projection: impl Into<List<FieldIdx>>) -> Path {
888 Path { loc, projection: projection.into() }
889 }
890
891 pub fn projection(&self) -> &[FieldIdx] {
892 &self.projection[..]
893 }
894
895 pub fn to_expr(&self) -> Expr {
896 self.projection
897 .iter()
898 .fold(self.loc.to_expr(), |e, f| Expr::path_proj(e, *f))
899 }
900
901 pub fn to_loc(&self) -> Option<Loc> {
902 if self.projection.is_empty() { Some(self.loc) } else { None }
903 }
904}
905
906impl Loc {
907 pub fn to_expr(&self) -> Expr {
908 match self {
909 Loc::Local(local) => Expr::local(*local),
910 Loc::Var(var) => Expr::var(*var),
911 }
912 }
913}
914
915macro_rules! impl_ops {
916 ($($op:ident: $method:ident),*) => {$(
917 impl<Rhs> std::ops::$op<Rhs> for Expr
918 where
919 Rhs: Into<Expr>,
920 {
921 type Output = Expr;
922
923 fn $method(self, rhs: Rhs) -> Self::Output {
924 let sort = crate::rty::Sort::Int;
925 Expr::binary_op(BinOp::$op(sort), self, rhs)
926 }
927 }
928
929 impl<Rhs> std::ops::$op<Rhs> for &Expr
930 where
931 Rhs: Into<Expr>,
932 {
933 type Output = Expr;
934
935 fn $method(self, rhs: Rhs) -> Self::Output {
936 let sort = crate::rty::Sort::Int;
937 Expr::binary_op(BinOp::$op(sort), self, rhs)
938 }
939 }
940 )*};
941}
942impl_ops!(Add: add, Sub: sub, Mul: mul, Div: div);
943
944impl From<i32> for Expr {
945 fn from(value: i32) -> Self {
946 Expr::constant(Constant::from(value))
947 }
948}
949
950impl From<&Expr> for Expr {
951 fn from(e: &Expr) -> Self {
952 e.clone()
953 }
954}
955
956impl From<Path> for Expr {
957 fn from(path: Path) -> Self {
958 path.to_expr()
959 }
960}
961
962impl From<Name> for Expr {
963 fn from(name: Name) -> Self {
964 Expr::fvar(name)
965 }
966}
967
968impl From<Var> for Expr {
969 fn from(var: Var) -> Self {
970 Expr::var(var)
971 }
972}
973
974impl From<Loc> for Path {
975 fn from(loc: Loc) -> Self {
976 Path::new(loc, vec![])
977 }
978}
979
980impl From<Name> for Loc {
981 fn from(name: Name) -> Self {
982 Loc::Var(Var::Free(name))
983 }
984}
985
986impl From<Local> for Loc {
987 fn from(local: Local) -> Self {
988 Loc::Local(local)
989 }
990}
991
992#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Encodable, Decodable)]
993pub struct Real(pub u128);
994
995impl liquid_fixpoint::FixpointFmt for Real {
996 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
997 write!(f, "{}.0", self.0)
998 }
999}
1000
1001#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Encodable, Decodable)]
1002pub enum Constant {
1003 Int(BigInt),
1004 Real(Real),
1005 Bool(bool),
1006 Str(Symbol),
1007 Char(char),
1008 BitVec(u128, u32),
1009}
1010
1011impl Constant {
1012 pub const ZERO: Constant = Constant::Int(BigInt::ZERO);
1013 pub const ONE: Constant = Constant::Int(BigInt::ONE);
1014 pub const TRUE: Constant = Constant::Bool(true);
1015
1016 fn to_bool(self) -> Option<bool> {
1017 match self {
1018 Constant::Bool(b) => Some(b),
1019 _ => None,
1020 }
1021 }
1022
1023 fn to_int(self) -> Option<BigInt> {
1024 match self {
1025 Constant::Int(n) => Some(n),
1026 _ => None,
1027 }
1028 }
1029
1030 pub fn iff(&self, other: &Constant) -> Option<Constant> {
1031 let b1 = self.to_bool()?;
1032 let b2 = other.to_bool()?;
1033 Some(Constant::Bool(b1 == b2))
1034 }
1035
1036 pub fn imp(&self, other: &Constant) -> Option<Constant> {
1037 let b1 = self.to_bool()?;
1038 let b2 = other.to_bool()?;
1039 Some(Constant::Bool(!b1 || b2))
1040 }
1041
1042 pub fn or(&self, other: &Constant) -> Option<Constant> {
1043 let b1 = self.to_bool()?;
1044 let b2 = other.to_bool()?;
1045 Some(Constant::Bool(b1 || b2))
1046 }
1047
1048 pub fn and(&self, other: &Constant) -> Option<Constant> {
1049 let b1 = self.to_bool()?;
1050 let b2 = other.to_bool()?;
1051 Some(Constant::Bool(b1 && b2))
1052 }
1053
1054 pub fn eq(&self, other: &Constant) -> Constant {
1055 Constant::Bool(*self == *other)
1056 }
1057
1058 pub fn ne(&self, other: &Constant) -> Constant {
1059 Constant::Bool(*self != *other)
1060 }
1061
1062 pub fn gt(&self, other: &Constant) -> Option<Constant> {
1063 let n1 = self.to_int()?;
1064 let n2 = other.to_int()?;
1065 Some(Constant::Bool(n1 > n2))
1066 }
1067
1068 pub fn ge(&self, other: &Constant) -> Option<Constant> {
1069 let n1 = self.to_int()?;
1070 let n2 = other.to_int()?;
1071 Some(Constant::Bool(n1 >= n2))
1072 }
1073
1074 pub fn from_scalar_int<'tcx, T>(tcx: TyCtxt<'tcx>, scalar: ScalarInt, t: &T) -> Option<Self>
1075 where
1076 T: ToRustc<'tcx, T = rustc_middle::ty::Ty<'tcx>>,
1077 {
1078 use rustc_middle::ty::TyKind;
1079 let ty = t.to_rustc(tcx);
1080 match ty.kind() {
1081 TyKind::Int(int_ty) => Some(Constant::from(scalar_to_int(tcx, scalar, *int_ty))),
1082 TyKind::Uint(uint_ty) => Some(Constant::from(scalar_to_uint(tcx, scalar, *uint_ty))),
1083 TyKind::Bool => {
1084 let b = scalar_to_bits(tcx, scalar, ty)?;
1085 Some(Constant::Bool(b != 0))
1086 }
1087 TyKind::Char => {
1088 let b = scalar_to_bits(tcx, scalar, ty)?;
1089 Some(Constant::Char(char::from_u32(b as u32)?))
1090 }
1091 _ => bug!(),
1092 }
1093 }
1094
1095 pub fn int_min(bit_width: u32) -> Constant {
1097 Constant::Int(BigInt::int_min(bit_width))
1098 }
1099
1100 pub fn int_max(bit_width: u32) -> Constant {
1102 Constant::Int(BigInt::int_max(bit_width))
1103 }
1104
1105 pub fn uint_max(bit_width: u32) -> Constant {
1107 Constant::Int(BigInt::uint_max(bit_width))
1108 }
1109}
1110
1111impl From<i32> for Constant {
1112 fn from(c: i32) -> Self {
1113 Constant::Int(c.into())
1114 }
1115}
1116
1117impl From<usize> for Constant {
1118 fn from(u: usize) -> Self {
1119 Constant::Int(u.into())
1120 }
1121}
1122
1123impl From<u128> for Constant {
1124 fn from(c: u128) -> Self {
1125 Constant::Int(c.into())
1126 }
1127}
1128
1129impl From<i128> for Constant {
1130 fn from(c: i128) -> Self {
1131 Constant::Int(c.into())
1132 }
1133}
1134
1135impl From<bool> for Constant {
1136 fn from(b: bool) -> Self {
1137 Constant::Bool(b)
1138 }
1139}
1140
1141impl From<Symbol> for Constant {
1142 fn from(s: Symbol) -> Self {
1143 Constant::Str(s)
1144 }
1145}
1146
1147impl From<char> for Constant {
1148 fn from(c: char) -> Self {
1149 Constant::Char(c)
1150 }
1151}
1152
1153impl_internable!(ExprKind);
1154impl_slice_internable!(Expr, KVar);
1155
1156#[derive(Debug)]
1157pub struct FieldBind<T> {
1158 pub name: Symbol,
1159 pub value: T,
1160}
1161
1162impl<T: Pretty> Pretty for FieldBind<T> {
1163 fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1164 w!(cx, f, "{}: {:?}", ^self.name, &self.value)
1165 }
1166}
1167
1168pub(crate) mod pretty {
1169 use flux_rustc_bridge::def_id_to_string;
1170
1171 use super::*;
1172 use crate::{name_of_thy_func, rty::pretty::nested_with_bound_vars};
1173
1174 #[derive(PartialEq, Eq, PartialOrd, Ord)]
1175 enum Precedence {
1176 Iff,
1177 Imp,
1178 Or,
1179 And,
1180 Cmp,
1181 Bitvec,
1182 AddSub,
1183 MulDiv,
1184 }
1185
1186 impl BinOp {
1187 fn precedence(&self) -> Precedence {
1188 match self {
1189 BinOp::Iff => Precedence::Iff,
1190 BinOp::Imp => Precedence::Imp,
1191 BinOp::Or => Precedence::Or,
1192 BinOp::And => Precedence::And,
1193 BinOp::Eq
1194 | BinOp::Ne
1195 | BinOp::Gt(_)
1196 | BinOp::Lt(_)
1197 | BinOp::Ge(_)
1198 | BinOp::Le(_) => Precedence::Cmp,
1199 BinOp::Add(_) | BinOp::Sub(_) => Precedence::AddSub,
1200 BinOp::Mul(_) | BinOp::Div(_) | BinOp::Mod(_) => Precedence::MulDiv,
1201 BinOp::BitAnd | BinOp::BitOr | BinOp::BitShl | BinOp::BitShr => Precedence::Bitvec,
1202 }
1203 }
1204 }
1205
1206 impl Precedence {
1207 pub fn is_associative(&self) -> bool {
1208 !matches!(self, Precedence::Imp | Precedence::Cmp)
1209 }
1210 }
1211
1212 pub fn should_parenthesize(op: &BinOp, child: &Expr) -> bool {
1213 if let ExprKind::BinaryOp(child_op, ..) = child.kind() {
1214 child_op.precedence() < op.precedence()
1215 || (child_op.precedence() == op.precedence() && !op.precedence().is_associative())
1216 } else {
1217 false
1218 }
1219 }
1220
1221 impl Pretty for Ctor {
1222 fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1223 match self {
1224 Ctor::Struct(def_id) => {
1225 w!(cx, f, "{:?}", def_id)
1226 }
1227 Ctor::Enum(def_id, variant_idx) => {
1228 w!(cx, f, "{:?}::{:?}", def_id, ^variant_idx)
1229 }
1230 }
1231 }
1232 }
1233
1234 impl Pretty for fhir::QuantKind {
1235 fn fmt(&self, _cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1236 match self {
1237 fhir::QuantKind::Exists => w!(cx, f, "∃"),
1238 fhir::QuantKind::Forall => w!(cx, f, "∀"),
1239 }
1240 }
1241 }
1242
1243 impl Pretty for Expr {
1244 fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1245 let e = if cx.simplify_exprs {
1246 self.simplify(&SnapshotMap::default())
1247 } else {
1248 self.clone()
1249 };
1250 match e.kind() {
1251 ExprKind::Var(var) => w!(cx, f, "{:?}", var),
1252 ExprKind::Local(local) => w!(cx, f, "{:?}", ^local),
1253 ExprKind::ConstDefId(did) => w!(cx, f, "{}", ^def_id_to_string(*did)),
1254 ExprKind::Constant(c) => w!(cx, f, "{:?}", c),
1255 ExprKind::BinaryOp(op, e1, e2) => {
1256 if should_parenthesize(op, e1) {
1257 w!(cx, f, "({:?})", e1)?;
1258 } else {
1259 w!(cx, f, "{:?}", e1)?;
1260 }
1261 if matches!(op, BinOp::Div(_)) {
1262 w!(cx, f, "{:?}", op)?;
1263 } else {
1264 w!(cx, f, " {:?} ", op)?;
1265 }
1266 if should_parenthesize(op, e2) {
1267 w!(cx, f, "({:?})", e2)?;
1268 } else {
1269 w!(cx, f, "{:?}", e2)?;
1270 }
1271 Ok(())
1272 }
1273 ExprKind::UnaryOp(op, e) => {
1274 if e.is_atom() {
1275 w!(cx, f, "{:?}{:?}", op, e)
1276 } else {
1277 w!(cx, f, "{:?}({:?})", op, e)
1278 }
1279 }
1280 ExprKind::FieldProj(e, proj) => {
1281 if e.is_atom() {
1282 w!(cx, f, "{:?}.{}", e, ^fmt_field_proj(cx, *proj))
1283 } else {
1284 w!(cx, f, "({:?}).{}", e, ^fmt_field_proj(cx, *proj))
1285 }
1286 }
1287 ExprKind::Tuple(flds) => {
1288 if let [e] = &flds[..] {
1289 w!(cx, f, "({:?},)", e)
1290 } else {
1291 w!(cx, f, "({:?})", join!(", ", flds))
1292 }
1293 }
1294 ExprKind::Ctor(ctor, flds) => {
1295 let def_id = ctor.def_id();
1296 if let Some(adt_sort_def) = cx.adt_sort_def_of(def_id) {
1297 let variant = adt_sort_def.variant(ctor.variant_idx()).field_names();
1298 let fields = iter::zip(variant, flds)
1299 .map(|(name, value)| FieldBind { name: *name, value: value.clone() })
1300 .collect_vec();
1301 match ctor {
1302 Ctor::Struct(_) => {
1303 w!(cx, f, "{:?} {{ {:?} }}", def_id, join!(", ", fields))
1304 }
1305 Ctor::Enum(_, idx) => {
1306 if fields.is_empty() {
1307 w!(cx, f, "{:?}::{:?}", def_id, ^idx.index())
1308 } else {
1309 w!(cx, f, "{:?}::{:?}({:?})", def_id, ^idx.index(), join!(", ", fields))
1310 }
1311 }
1312 }
1313 } else {
1314 match ctor {
1315 Ctor::Struct(_) => {
1316 w!(cx, f, "{:?} {{ {:?} }}", def_id, join!(", ", flds))
1317 }
1318 Ctor::Enum(_, idx) => {
1319 w!(cx, f, "{:?}::{:?} {{ {:?} }}", def_id, ^idx, join!(", ", flds))
1320 }
1321 }
1322 }
1323 }
1324 ExprKind::PathProj(e, field) => {
1325 if e.is_atom() {
1326 w!(cx, f, "{:?}.{:?}", e, field)
1327 } else {
1328 w!(cx, f, "({:?}).{:?}", e, field)
1329 }
1330 }
1331 ExprKind::App(func, args) => {
1332 w!(cx, f, "{:?}({})",
1333 parens!(func, !func.is_atom()),
1334 ^args
1335 .iter()
1336 .format_with(", ", |arg, f| f(&format_args_cx!(cx, "{:?}", arg)))
1337 )
1338 }
1339 ExprKind::IfThenElse(p, e1, e2) => {
1340 w!(cx, f, "if {:?} {{ {:?} }} else {{ {:?} }}", p, e1, e2)
1341 }
1342 ExprKind::Hole(_) => {
1343 w!(cx, f, "*")
1344 }
1345 ExprKind::KVar(kvar) => {
1346 w!(cx, f, "{:?}", kvar)
1347 }
1348 ExprKind::Alias(alias, args) => {
1349 w!(cx, f, "{:?}({:?})", alias, join!(", ", args))
1350 }
1351 ExprKind::Abs(lam) => {
1352 w!(cx, f, "{:?}", lam)
1353 }
1354 ExprKind::GlobalFunc(SpecFuncKind::Def(did) | SpecFuncKind::Uif(did)) => {
1355 w!(cx, f, "{}", ^did.name())
1356 }
1357 ExprKind::GlobalFunc(SpecFuncKind::Thy(itf)) => {
1358 if let Some(name) = name_of_thy_func(*itf) {
1359 w!(cx, f, "{}", ^name)
1360 } else {
1361 w!(cx, f, "<error>")
1362 }
1363 }
1364 ExprKind::ForAll(expr) => {
1365 let vars = expr.vars();
1366 cx.with_bound_vars(vars, || {
1367 if !vars.is_empty() {
1368 cx.fmt_bound_vars(false, "∀", vars, ". ", f)?;
1369 }
1370 w!(cx, f, "{:?}", expr.skip_binder_ref())
1371 })
1372 }
1373 ExprKind::BoundedQuant(kind, rng, body) => {
1374 let vars = body.vars();
1375 cx.with_bound_vars(vars, || {
1376 w!(
1377 cx,
1378 f,
1379 "{:?} {}..{} {{ {:?} }}",
1380 kind,
1381 ^rng.start,
1382 ^rng.end,
1383 body.skip_binder_ref()
1384 )
1385 })
1386 }
1387 ExprKind::Let(init, body) => {
1388 let vars = body.vars();
1389 cx.with_bound_vars(vars, || {
1390 cx.fmt_bound_vars(false, "(let ", vars, " = ", f)?;
1391 w!(cx, f, "{:?} in {:?})", init, body.skip_binder_ref())
1392 })
1393 }
1394 }
1395 }
1396 }
1397
1398 fn fmt_field_proj(cx: &PrettyCx, proj: FieldProj) -> String {
1399 if let FieldProj::Adt { def_id, field } = proj
1400 && let Some(adt_sort_def) = cx.adt_sort_def_of(def_id)
1401 {
1402 format!("{}", adt_sort_def.struct_variant().field_names()[field as usize])
1403 } else {
1404 format!("{}", proj.field_idx())
1405 }
1406 }
1407
1408 impl Pretty for Constant {
1409 fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1410 match self {
1411 Constant::Int(i) => w!(cx, f, "{i}"),
1412 Constant::BitVec(i, sz) => w!(cx, f, "bv({i}, {sz})"),
1413 Constant::Real(r) => w!(cx, f, "{}.0", ^r.0),
1414 Constant::Bool(b) => w!(cx, f, "{b}"),
1415 Constant::Str(sym) => w!(cx, f, "\"{sym}\""),
1416 Constant::Char(c) => w!(cx, f, "\'{c}\'"),
1417 }
1418 }
1419 }
1420
1421 impl Pretty for AliasReft {
1422 fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1423 w!(cx, f, "<({:?}) as {:?}", &self.args[0], self.assoc_id.parent())?;
1424 let args = &self.args[1..];
1425 if !args.is_empty() {
1426 w!(cx, f, "<{:?}>", join!(", ", args))?;
1427 }
1428 w!(cx, f, ">::{}", ^self.assoc_id.name())
1429 }
1430 }
1431
1432 impl Pretty for Lambda {
1433 fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1434 let vars = self.body.vars();
1435 cx.with_bound_vars(vars, || {
1436 cx.fmt_bound_vars(false, "λ", vars, ". ", f)?;
1437 w!(cx, f, "{:?}", self.body.as_ref().skip_binder())
1438 })
1439 }
1440 }
1441
1442 impl Pretty for Var {
1443 fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1444 match self {
1445 Var::Bound(debruijn, var) => cx.fmt_bound_reft(*debruijn, *var, f),
1446 Var::EarlyParam(var) => w!(cx, f, "{}", ^var.name),
1447 Var::Free(name) => w!(cx, f, "{:?}", ^name),
1448 Var::EVar(evar) => w!(cx, f, "{:?}", ^evar),
1449 Var::ConstGeneric(param) => w!(cx, f, "{}", ^param.name),
1450 }
1451 }
1452 }
1453
1454 impl Pretty for KVar {
1455 fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1456 w!(cx, f, "{:?}", ^self.kvid)?;
1457 match cx.kvar_args {
1458 KVarArgs::All => {
1459 w!(
1460 cx,
1461 f,
1462 "({:?})[{:?}]",
1463 join!(", ", self.self_args()),
1464 join!(", ", self.scope())
1465 )?;
1466 }
1467 KVarArgs::SelfOnly => w!(cx, f, "({:?})", join!(", ", self.self_args()))?,
1468 KVarArgs::Hide => {}
1469 }
1470 Ok(())
1471 }
1472 }
1473
1474 impl Pretty for Path {
1475 fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1476 w!(cx, f, "{:?}", &self.loc)?;
1477 for field in &self.projection {
1478 w!(cx, f, ".{}", ^u32::from(*field))?;
1479 }
1480 Ok(())
1481 }
1482 }
1483
1484 impl Pretty for Loc {
1485 fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1486 match self {
1487 Loc::Local(local) => w!(cx, f, "{:?}", ^local),
1488 Loc::Var(var) => w!(cx, f, "{:?}", var),
1489 }
1490 }
1491 }
1492
1493 impl Pretty for BinOp {
1494 fn fmt(&self, _cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1495 match self {
1496 BinOp::Iff => w!(cx, f, "⇔"),
1497 BinOp::Imp => w!(cx, f, "⇒"),
1498 BinOp::Or => w!(cx, f, "∨"),
1499 BinOp::And => w!(cx, f, "∧"),
1500 BinOp::Eq => w!(cx, f, "="),
1501 BinOp::Ne => w!(cx, f, "≠"),
1502 BinOp::Gt(_) => w!(cx, f, ">"),
1503 BinOp::Ge(_) => w!(cx, f, "≥"),
1504 BinOp::Lt(_) => w!(cx, f, "<"),
1505 BinOp::Le(_) => w!(cx, f, "≤"),
1506 BinOp::Add(_) => w!(cx, f, "+"),
1507 BinOp::Sub(_) => w!(cx, f, "-"),
1508 BinOp::Mul(_) => w!(cx, f, "*"),
1509 BinOp::Div(_) => w!(cx, f, "/"),
1510 BinOp::Mod(_) => w!(cx, f, "mod"),
1511 BinOp::BitAnd => w!(cx, f, "&"),
1512 BinOp::BitOr => w!(cx, f, "|"),
1513 BinOp::BitShl => w!(cx, f, "<<"),
1514 BinOp::BitShr => w!(cx, f, ">>"),
1515 }
1516 }
1517 }
1518
1519 impl Pretty for UnOp {
1520 fn fmt(&self, _cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1521 match self {
1522 UnOp::Not => w!(cx, f, "¬"),
1523 UnOp::Neg => w!(cx, f, "-"),
1524 }
1525 }
1526 }
1527
1528 impl_debug_with_default_cx!(Expr, Loc, Path, Var, KVar, Lambda, AliasReft);
1529
1530 impl PrettyNested for Lambda {
1531 fn fmt_nested(&self, cx: &PrettyCx) -> Result<NestedString, fmt::Error> {
1532 nested_with_bound_vars(cx, "λ", self.body.vars(), None, |prefix| {
1533 let expr_d = self.body.skip_binder_ref().fmt_nested(cx)?;
1534 let text = format!("{}{}", prefix, expr_d.text);
1535 Ok(NestedString { text, children: expr_d.children, key: None })
1536 })
1537 }
1538 }
1539
1540 pub fn aggregate_nested(
1541 cx: &PrettyCx,
1542 ctor: &Ctor,
1543 flds: &[Expr],
1544 is_named: bool,
1545 ) -> Result<NestedString, fmt::Error> {
1546 let def_id = ctor.def_id();
1547 let mut text =
1548 if is_named && ctor.is_enum() { format_cx!(cx, "{:?}", ctor) } else { "".to_string() };
1549 if flds.is_empty() {
1550 Ok(NestedString { text, children: None, key: None })
1552 } else if flds.len() == 1 {
1553 text += &format_cx!(cx, "{:?} ", flds[0].clone());
1555 Ok(NestedString { text, children: None, key: None })
1556 } else {
1557 let keys = if let Some(adt_sort_def) = cx.adt_sort_def_of(def_id) {
1558 adt_sort_def
1559 .variant(ctor.variant_idx())
1560 .field_names()
1561 .iter()
1562 .map(|name| format!("{}", name))
1563 .collect_vec()
1564 } else {
1565 (0..flds.len()).map(|i| format!("arg{}", i)).collect_vec()
1566 };
1567 text += "{..}";
1569 let mut children = vec![];
1570 for (key, fld) in iter::zip(keys, flds) {
1571 let fld_d = fld.fmt_nested(cx)?;
1572 children.push(NestedString { key: Some(key), ..fld_d });
1573 }
1574 Ok(NestedString { text, children: Some(children), key: None })
1575 }
1576 }
1577
1578 impl PrettyNested for Expr {
1579 fn fmt_nested(&self, cx: &PrettyCx) -> Result<NestedString, fmt::Error> {
1580 let e = if cx.simplify_exprs {
1581 self.simplify(&SnapshotMap::default())
1582 } else {
1583 self.clone()
1584 };
1585 match e.kind() {
1586 ExprKind::Var(..)
1587 | ExprKind::Local(..)
1588 | ExprKind::Constant(..)
1589 | ExprKind::ConstDefId(..)
1590 | ExprKind::Hole(..)
1591 | ExprKind::GlobalFunc(..)
1592 | ExprKind::KVar(..) => debug_nested(cx, &e),
1593
1594 ExprKind::IfThenElse(p, e1, e2) => {
1595 let p_d = p.fmt_nested(cx)?;
1596 let e1_d = e1.fmt_nested(cx)?;
1597 let e2_d = e2.fmt_nested(cx)?;
1598 let text = format!("(if {} then {} else {})", p_d.text, e1_d.text, e2_d.text);
1599 let children = float_children(vec![p_d.children, e1_d.children, e2_d.children]);
1600 Ok(NestedString { text, children, key: None })
1601 }
1602 ExprKind::BinaryOp(op, e1, e2) => {
1603 let e1_d = e1.fmt_nested(cx)?;
1604 let e2_d = e2.fmt_nested(cx)?;
1605 let e1_text = if should_parenthesize(op, e1) {
1606 format!("({})", e1_d.text)
1607 } else {
1608 e1_d.text
1609 };
1610 let e2_text = if should_parenthesize(op, e2) {
1611 format!("({})", e2_d.text)
1612 } else {
1613 e2_d.text
1614 };
1615 let op_d = debug_nested(cx, op)?;
1616 let op_text = if matches!(op, BinOp::Div(_)) {
1617 op_d.text
1618 } else {
1619 format!(" {} ", op_d.text)
1620 };
1621 let text = format!("{}{}{}", e1_text, op_text, e2_text);
1622 let children = float_children(vec![e1_d.children, e2_d.children]);
1623 Ok(NestedString { text, children, key: None })
1624 }
1625 ExprKind::UnaryOp(op, e) => {
1626 let e_d = e.fmt_nested(cx)?;
1627 let op_d = debug_nested(cx, op)?;
1628 let text = if e.is_atom() {
1629 format!("{}{}", op_d.text, e_d.text)
1630 } else {
1631 format!("{}({})", op_d.text, e_d.text)
1632 };
1633 Ok(NestedString { text, children: e_d.children, key: None })
1634 }
1635 ExprKind::FieldProj(e, proj) => {
1636 let e_d = e.fmt_nested(cx)?;
1637 let text = if e.is_atom() {
1638 format!("{}.{}", e_d.text, fmt_field_proj(cx, *proj))
1639 } else {
1640 format!("({}).{}", e_d.text, fmt_field_proj(cx, *proj))
1641 };
1642 Ok(NestedString { text, children: e_d.children, key: None })
1643 }
1644 ExprKind::Tuple(flds) => {
1645 let mut texts = vec![];
1646 let mut kidss = vec![];
1647 for e in flds {
1648 let e_d = e.fmt_nested(cx)?;
1649 texts.push(e_d.text);
1650 kidss.push(e_d.children);
1651 }
1652 let text = if let [e] = &texts[..] {
1653 format!("({},)", e)
1654 } else {
1655 format!("({})", texts.join(", "))
1656 };
1657 let children = float_children(kidss);
1658 Ok(NestedString { text, children, key: None })
1659 }
1660 ExprKind::Ctor(ctor, flds) => aggregate_nested(cx, ctor, flds, true),
1661 ExprKind::PathProj(e, field) => {
1662 let e_d = e.fmt_nested(cx)?;
1663 let text = if e.is_atom() {
1664 format!("{}.{:?}", e_d.text, field)
1665 } else {
1666 format!("({}).{:?}", e_d.text, field)
1667 };
1668 Ok(NestedString { text, children: e_d.children, key: None })
1669 }
1670 ExprKind::Alias(alias, args) => {
1671 let mut texts = vec![];
1672 let mut kidss = vec![];
1673 for arg in args {
1674 let arg_d = arg.fmt_nested(cx)?;
1675 texts.push(arg_d.text);
1676 kidss.push(arg_d.children);
1677 }
1678 let text = format_cx!(cx, "{:?}({:?})", alias, texts.join(", "));
1679 let children = float_children(kidss);
1680 Ok(NestedString { text, children, key: None })
1681 }
1682 ExprKind::App(func, args) => {
1683 let func_d = func.fmt_nested(cx)?;
1684 let mut texts = vec![];
1685 let mut kidss = vec![func_d.children];
1686 for arg in args {
1687 let arg_d = arg.fmt_nested(cx)?;
1688 texts.push(arg_d.text);
1689 kidss.push(arg_d.children);
1690 }
1691 let text = if func.is_atom() {
1692 format!("{}({})", func_d.text, texts.join(", "))
1693 } else {
1694 format!("({})({})", func_d.text, texts.join(", "))
1695 };
1696 let children = float_children(kidss);
1697 Ok(NestedString { text, children, key: None })
1698 }
1699 ExprKind::Abs(lambda) => lambda.fmt_nested(cx),
1700 ExprKind::Let(init, body) => {
1701 nested_with_bound_vars(cx, "let", body.vars(), None, |prefix| {
1703 let body = body.skip_binder_ref().fmt_nested(cx)?;
1704 let text = format!("{:?} {}{}", init, prefix, body.text);
1705 Ok(NestedString { text, children: body.children, key: None })
1706 })
1707 }
1708 ExprKind::BoundedQuant(kind, rng, body) => {
1709 let left = match kind {
1710 fhir::QuantKind::Forall => "∀",
1711 fhir::QuantKind::Exists => "∃",
1712 };
1713 let right = Some(format!(" in {}..{}", rng.start, rng.end));
1714
1715 nested_with_bound_vars(cx, left, body.vars(), right, |all_str| {
1716 let expr_d = body.as_ref().skip_binder().fmt_nested(cx)?;
1717 let text = format!("{}{}", all_str, expr_d.text);
1718 Ok(NestedString { text, children: expr_d.children, key: None })
1719 })
1720 }
1721 ExprKind::ForAll(expr) => {
1722 nested_with_bound_vars(cx, "∀", expr.vars(), None, |all_str| {
1723 let expr_d = expr.as_ref().skip_binder().fmt_nested(cx)?;
1724 let text = format!("{}{}", all_str, expr_d.text);
1725 Ok(NestedString { text, children: expr_d.children, key: None })
1726 })
1727 }
1728 }
1729 }
1730 }
1731}