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