flux_middle/rty/
expr.rs

1use std::{fmt, hash::Hash, iter, ops::ControlFlow, sync::OnceLock};
2
3use flux_arc_interner::{Interned, List, impl_internable, impl_slice_internable};
4use flux_common::{bug, dbg::as_subscript};
5use flux_macros::{TypeFoldable, TypeVisitable};
6use flux_rustc_bridge::{
7    ToRustc,
8    const_eval::{scalar_to_bits, scalar_to_int, scalar_to_uint},
9    ty::{Const, ConstKind, ValTree, VariantIdx},
10};
11use itertools::Itertools;
12use liquid_fixpoint::ThyFunc;
13use rustc_abi::{FIRST_VARIANT, FieldIdx};
14use rustc_data_structures::{fx::FxHashMap, snapshot_map::SnapshotMap};
15use rustc_hir::def_id::DefId;
16use rustc_index::newtype_index;
17use rustc_macros::{Decodable, Encodable, TyDecodable, TyEncodable};
18use rustc_middle::{
19    mir::Local,
20    ty::{ParamConst, ScalarInt, TyCtxt},
21};
22use rustc_span::{Span, Symbol};
23use rustc_type_ir::{BoundVar, DebruijnIndex, INNERMOST};
24
25use super::{
26    BaseTy, Binder, BoundReftKind, BoundVariableKinds, FuncSort, GenericArgs, GenericArgsExt as _,
27    IntTy, Sort, UintTy,
28};
29use crate::{
30    big_int::BigInt,
31    def_id::FluxDefId,
32    fhir::{self},
33    global_env::GlobalEnv,
34    pretty::*,
35    queries::QueryResult,
36    rty::{
37        BoundVariableKind, SortArg, SubsetTyCtor,
38        fold::{
39            TypeFoldable, TypeFolder, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable as _,
40            TypeVisitor,
41        },
42    },
43};
44
45/// A lambda abstraction with an elaborated output sort. We need the output sort of lambdas for
46/// encoding into fixpoint
47#[derive(Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, TypeVisitable, TypeFoldable)]
48pub struct Lambda {
49    body: Binder<Expr>,
50    output: Sort,
51}
52
53impl Lambda {
54    pub fn bind_with_vars(body: Expr, inputs: BoundVariableKinds, output: Sort) -> Self {
55        debug_assert!(inputs.iter().all(BoundVariableKind::is_refine));
56        Self { body: Binder::bind_with_vars(body, inputs), output }
57    }
58
59    pub fn bind_with_fsort(body: Expr, fsort: FuncSort) -> Self {
60        Self { body: Binder::bind_with_sorts(body, fsort.inputs()), output: fsort.output().clone() }
61    }
62
63    pub fn apply(&self, args: &[Expr]) -> Expr {
64        self.body.replace_bound_refts(args)
65    }
66
67    pub fn vars(&self) -> &BoundVariableKinds {
68        self.body.vars()
69    }
70
71    pub fn output(&self) -> Sort {
72        self.output.clone()
73    }
74
75    pub fn fsort(&self) -> FuncSort {
76        let inputs_and_output = self
77            .vars()
78            .iter()
79            .map(|kind| kind.expect_sort().clone())
80            .chain(iter::once(self.output()))
81            .collect();
82        FuncSort { inputs_and_output }
83    }
84}
85
86#[derive(Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, TypeVisitable, TypeFoldable)]
87pub struct AliasReft {
88    /// Id of the associated refinement in the trait
89    pub assoc_id: FluxDefId,
90    pub args: GenericArgs,
91}
92
93impl AliasReft {
94    pub fn self_ty(&self) -> SubsetTyCtor {
95        self.args[0].expect_base().clone()
96    }
97
98    pub fn to_rustc_trait_ref<'tcx>(&self, tcx: TyCtxt<'tcx>) -> rustc_middle::ty::TraitRef<'tcx> {
99        let trait_def_id = self.assoc_id.parent();
100        let args = self
101            .args
102            .to_rustc(tcx)
103            .truncate_to(tcx, tcx.generics_of(trait_def_id));
104        rustc_middle::ty::TraitRef::new(tcx, trait_def_id, args)
105    }
106}
107
108#[derive(Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
109pub struct Expr {
110    kind: Interned<ExprKind>,
111    espan: Option<ESpan>,
112}
113
114impl Expr {
115    pub fn at_opt(self, espan: Option<ESpan>) -> Expr {
116        Expr { kind: self.kind, espan }
117    }
118
119    pub fn at(self, espan: ESpan) -> Expr {
120        self.at_opt(Some(espan))
121    }
122
123    pub fn at_base(self, base: ESpan) -> Expr {
124        if let Some(espan) = self.espan { self.at(espan.with_base(base)) } else { self }
125    }
126
127    pub fn span(&self) -> Option<ESpan> {
128        self.espan
129    }
130
131    pub fn tt() -> Expr {
132        static TRUE: OnceLock<Expr> = OnceLock::new();
133        TRUE.get_or_init(|| ExprKind::Constant(Constant::Bool(true)).intern())
134            .clone()
135    }
136
137    pub fn ff() -> Expr {
138        static FALSE: OnceLock<Expr> = OnceLock::new();
139        FALSE
140            .get_or_init(|| ExprKind::Constant(Constant::Bool(false)).intern())
141            .clone()
142    }
143
144    pub fn and_from_iter(exprs: impl IntoIterator<Item = Expr>) -> Expr {
145        exprs
146            .into_iter()
147            .reduce(|acc, e| Expr::binary_op(BinOp::And, acc, e))
148            .unwrap_or_else(Expr::tt)
149    }
150
151    pub fn or_from_iter(exprs: impl IntoIterator<Item = Expr>) -> Expr {
152        exprs
153            .into_iter()
154            .reduce(|acc, e| Expr::binary_op(BinOp::Or, acc, e))
155            .unwrap_or_else(Expr::ff)
156    }
157
158    pub fn and(e1: impl Into<Expr>, e2: impl Into<Expr>) -> Expr {
159        Expr::and_from_iter([e1.into(), e2.into()])
160    }
161
162    pub fn or(e1: impl Into<Expr>, e2: impl Into<Expr>) -> Expr {
163        Expr::or_from_iter([e1.into(), e2.into()])
164    }
165
166    pub fn zero() -> Expr {
167        static ZERO: OnceLock<Expr> = OnceLock::new();
168        ZERO.get_or_init(|| ExprKind::Constant(Constant::ZERO).intern())
169            .clone()
170    }
171
172    pub fn int_max(int_ty: IntTy) -> Expr {
173        let bit_width: u64 = int_ty
174            .bit_width()
175            .unwrap_or(flux_config::pointer_width().bits());
176        Expr::constant(Constant::int_max(bit_width.try_into().unwrap()))
177    }
178
179    pub fn int_min(int_ty: IntTy) -> Expr {
180        let bit_width: u64 = int_ty
181            .bit_width()
182            .unwrap_or(flux_config::pointer_width().bits());
183        Expr::constant(Constant::int_min(bit_width.try_into().unwrap()))
184    }
185
186    pub fn uint_max(uint_ty: UintTy) -> Expr {
187        let bit_width: u64 = uint_ty
188            .bit_width()
189            .unwrap_or(flux_config::pointer_width().bits());
190        Expr::constant(Constant::uint_max(bit_width.try_into().unwrap()))
191    }
192
193    pub fn nu() -> Expr {
194        Expr::bvar(INNERMOST, BoundVar::ZERO, BoundReftKind::Anon)
195    }
196
197    pub fn is_nu(&self) -> bool {
198        if let ExprKind::Var(Var::Bound(INNERMOST, var)) = self.kind()
199            && var.var == BoundVar::ZERO
200        {
201            true
202        } else {
203            false
204        }
205    }
206
207    pub fn unit() -> Expr {
208        Expr::tuple(List::empty())
209    }
210
211    pub fn var(var: Var) -> Expr {
212        ExprKind::Var(var).intern()
213    }
214
215    pub fn fvar(name: Name) -> Expr {
216        Var::Free(name).to_expr()
217    }
218
219    pub fn evar(evid: EVid) -> Expr {
220        Var::EVar(evid).to_expr()
221    }
222
223    pub fn bvar(debruijn: DebruijnIndex, var: BoundVar, kind: BoundReftKind) -> Expr {
224        Var::Bound(debruijn, BoundReft { var, kind }).to_expr()
225    }
226
227    pub fn early_param(index: u32, name: Symbol) -> Expr {
228        Var::EarlyParam(EarlyReftParam { index, name }).to_expr()
229    }
230
231    pub fn local(local: Local) -> Expr {
232        ExprKind::Local(local).intern()
233    }
234
235    pub fn constant(c: Constant) -> Expr {
236        ExprKind::Constant(c).intern()
237    }
238
239    pub fn const_def_id(c: DefId) -> Expr {
240        ExprKind::ConstDefId(c).intern()
241    }
242
243    pub fn const_generic(param: ParamConst) -> Expr {
244        ExprKind::Var(Var::ConstGeneric(param)).intern()
245    }
246
247    pub fn tuple(flds: List<Expr>) -> Expr {
248        ExprKind::Tuple(flds).intern()
249    }
250
251    pub fn ctor_struct(def_id: DefId, flds: List<Expr>) -> Expr {
252        ExprKind::Ctor(Ctor::Struct(def_id), flds).intern()
253    }
254
255    pub fn ctor_enum(def_id: DefId, idx: VariantIdx) -> Expr {
256        ExprKind::Ctor(Ctor::Enum(def_id, idx), List::empty()).intern()
257    }
258
259    pub fn ctor(ctor: Ctor, flds: List<Expr>) -> Expr {
260        ExprKind::Ctor(ctor, flds).intern()
261    }
262
263    pub fn is_ctor(def_id: DefId, variant_idx: VariantIdx, idx: impl Into<Expr>) -> Expr {
264        ExprKind::IsCtor(def_id, variant_idx, idx.into()).intern()
265    }
266
267    pub fn from_bits(bty: &BaseTy, bits: u128) -> Expr {
268        // FIXME: We are assuming the higher bits are not set. check this assumption
269        match bty {
270            BaseTy::Int(_) => {
271                let bits = bits as i128;
272                ExprKind::Constant(Constant::from(bits)).intern()
273            }
274            BaseTy::Uint(_) => ExprKind::Constant(Constant::from(bits)).intern(),
275            BaseTy::Bool => ExprKind::Constant(Constant::Bool(bits != 0)).intern(),
276            BaseTy::Char => {
277                let c = char::from_u32(bits.try_into().unwrap()).unwrap();
278                ExprKind::Constant(Constant::Char(c)).intern()
279            }
280            _ => bug!(),
281        }
282    }
283
284    pub fn ite(p: impl Into<Expr>, e1: impl Into<Expr>, e2: impl Into<Expr>) -> Expr {
285        ExprKind::IfThenElse(p.into(), e1.into(), e2.into()).intern()
286    }
287
288    fn empty() -> Expr {
289        let func = Self::global_func(SpecFuncKind::Thy(ThyFunc::SetEmpty));
290        Expr::app(func, List::empty(), List::from_arr([Expr::zero()]))
291    }
292
293    fn singleton(elem: Expr) -> Expr {
294        let func = Self::global_func(SpecFuncKind::Thy(ThyFunc::SetSng));
295        Expr::app(func, List::empty(), List::from_arr([elem]))
296    }
297
298    fn union(expr1: Expr, expr2: Expr) -> Expr {
299        let func = Self::global_func(SpecFuncKind::Thy(ThyFunc::SetCup));
300        Expr::app(func, List::empty(), List::from_arr([expr1, expr2]))
301    }
302
303    pub fn set(elems: List<Expr>) -> Expr {
304        let mut expr = Expr::empty();
305        for elem in &elems {
306            expr = Self::union(expr, Self::singleton(elem.clone()));
307        }
308        expr
309    }
310
311    pub fn abs(lam: Lambda) -> Expr {
312        ExprKind::Abs(lam).intern()
313    }
314
315    pub fn let_(init: Expr, body: Binder<Expr>) -> Expr {
316        ExprKind::Let(init, body).intern()
317    }
318
319    pub fn bounded_quant(kind: fhir::QuantKind, rng: fhir::Range, body: Binder<Expr>) -> Expr {
320        ExprKind::BoundedQuant(kind, rng, body).intern()
321    }
322
323    pub fn hole(kind: HoleKind) -> Expr {
324        ExprKind::Hole(kind).intern()
325    }
326
327    pub fn kvar(kvar: KVar) -> Expr {
328        ExprKind::KVar(kvar).intern()
329    }
330
331    pub fn alias(alias: AliasReft, args: List<Expr>) -> Expr {
332        ExprKind::Alias(alias, args).intern()
333    }
334
335    pub fn forall(expr: Binder<Expr>) -> Expr {
336        ExprKind::ForAll(expr).intern()
337    }
338
339    pub fn exists(expr: Binder<Expr>) -> Expr {
340        ExprKind::Exists(expr).intern()
341    }
342
343    pub fn binary_op(op: BinOp, e1: impl Into<Expr>, e2: impl Into<Expr>) -> Expr {
344        ExprKind::BinaryOp(op, e1.into(), e2.into()).intern()
345    }
346
347    pub fn prim_val(op: BinOp, e1: impl Into<Expr>, e2: impl Into<Expr>) -> Expr {
348        Expr::app(InternalFuncKind::Val(op), List::empty(), List::from_arr([e1.into(), e2.into()]))
349    }
350
351    pub fn prim_rel(op: BinOp, e1: impl Into<Expr>, e2: impl Into<Expr>) -> Expr {
352        Expr::app(InternalFuncKind::Rel(op), List::empty(), List::from_arr([e1.into(), e2.into()]))
353    }
354
355    pub fn unit_struct(def_id: DefId) -> Expr {
356        Expr::ctor_struct(def_id, List::empty())
357    }
358
359    pub fn cast(from: Sort, to: Sort, idx: Expr) -> Expr {
360        Expr::app(
361            InternalFuncKind::Cast,
362            List::from_arr([SortArg::Sort(from), SortArg::Sort(to)]),
363            List::from_arr([idx]),
364        )
365    }
366
367    pub fn app(func: impl Into<Expr>, sort_args: List<SortArg>, args: List<Expr>) -> Expr {
368        ExprKind::App(func.into(), sort_args, args).intern()
369    }
370
371    pub fn global_func(kind: SpecFuncKind) -> Expr {
372        ExprKind::GlobalFunc(kind).intern()
373    }
374
375    pub fn internal_func(kind: InternalFuncKind) -> Expr {
376        ExprKind::InternalFunc(kind).intern()
377    }
378
379    pub fn eq(e1: impl Into<Expr>, e2: impl Into<Expr>) -> Expr {
380        ExprKind::BinaryOp(BinOp::Eq, e1.into(), e2.into()).intern()
381    }
382
383    pub fn unary_op(op: UnOp, e: impl Into<Expr>) -> Expr {
384        ExprKind::UnaryOp(op, e.into()).intern()
385    }
386
387    pub fn ne(e1: impl Into<Expr>, e2: impl Into<Expr>) -> Expr {
388        ExprKind::BinaryOp(BinOp::Ne, e1.into(), e2.into()).intern()
389    }
390
391    pub fn ge(e1: impl Into<Expr>, e2: impl Into<Expr>) -> Expr {
392        ExprKind::BinaryOp(BinOp::Ge(Sort::Int), e1.into(), e2.into()).intern()
393    }
394
395    pub fn gt(e1: impl Into<Expr>, e2: impl Into<Expr>) -> Expr {
396        ExprKind::BinaryOp(BinOp::Gt(Sort::Int), e1.into(), e2.into()).intern()
397    }
398
399    pub fn lt(e1: impl Into<Expr>, e2: impl Into<Expr>) -> Expr {
400        ExprKind::BinaryOp(BinOp::Lt(Sort::Int), e1.into(), e2.into()).intern()
401    }
402
403    pub fn le(e1: impl Into<Expr>, e2: impl Into<Expr>) -> Expr {
404        ExprKind::BinaryOp(BinOp::Le(Sort::Int), e1.into(), e2.into()).intern()
405    }
406
407    pub fn implies(e1: impl Into<Expr>, e2: impl Into<Expr>) -> Expr {
408        ExprKind::BinaryOp(BinOp::Imp, e1.into(), e2.into()).intern()
409    }
410
411    pub fn field_proj(e: impl Into<Expr>, proj: FieldProj) -> Expr {
412        ExprKind::FieldProj(e.into(), proj).intern()
413    }
414
415    pub fn field_projs(e: impl Into<Expr>, projs: &[FieldProj]) -> Expr {
416        projs.iter().copied().fold(e.into(), Expr::field_proj)
417    }
418
419    pub fn path_proj(base: Expr, field: FieldIdx) -> Expr {
420        ExprKind::PathProj(base, field).intern()
421    }
422
423    pub fn not(&self) -> Expr {
424        ExprKind::UnaryOp(UnOp::Not, self.clone()).intern()
425    }
426
427    pub fn neg(&self) -> Expr {
428        ExprKind::UnaryOp(UnOp::Neg, self.clone()).intern()
429    }
430
431    pub fn kind(&self) -> &ExprKind {
432        &self.kind
433    }
434
435    /// An expression is an *atom* if it is "self-delimiting", i.e., it has a clear boundary
436    /// when printed. This is used to avoid unnecessary parenthesis when pretty printing.
437    pub fn is_atom(&self) -> bool {
438        !matches!(self.kind(), ExprKind::Abs(..) | ExprKind::BinaryOp(..) | ExprKind::ForAll(..))
439    }
440
441    /// Simple syntactic check to see if the expression is a trivially true predicate. This is used
442    /// mostly for filtering predicates when pretty printing but also to simplify types in general.
443    pub fn is_trivially_true(&self) -> bool {
444        self.is_true()
445            || matches!(self.kind(), ExprKind::BinaryOp(BinOp::Eq | BinOp::Iff | BinOp::Imp, e1, e2) if e1.erase_spans() == e2.erase_spans())
446    }
447
448    /// Simple syntactic check to see if the expression is a trivially false predicate.
449    pub fn is_trivially_false(&self) -> bool {
450        self.is_false()
451    }
452
453    /// Whether the expression is *literally* the constant `true`.
454    fn is_true(&self) -> bool {
455        matches!(self.kind(), ExprKind::Constant(Constant::Bool(true)))
456    }
457
458    /// Whether the expression is *literally* the constant `false`.
459    fn is_false(&self) -> bool {
460        matches!(self.kind(), ExprKind::Constant(Constant::Bool(false)))
461    }
462
463    pub fn from_const(tcx: TyCtxt, c: &Const) -> Expr {
464        match &c.kind {
465            ConstKind::Param(param_const) => Expr::const_generic(*param_const),
466            ConstKind::Value(ty, ValTree::Leaf(scalar)) => {
467                Expr::constant(Constant::from_scalar_int(tcx, *scalar, ty).unwrap())
468            }
469            ConstKind::Value(_ty, ValTree::Branch(_)) => {
470                bug!("todo: ValTree::Branch {c:?}")
471            }
472            // We should have normalized away the unevaluated constants
473            ConstKind::Unevaluated(_) => bug!("unexpected `ConstKind::Unevaluated`"),
474
475            ConstKind::Infer(_) => bug!("unexpected `ConstKind::Infer`"),
476        }
477    }
478
479    fn const_op(op: &BinOp, c1: &Constant, c2: &Constant) -> Option<Constant> {
480        match op {
481            BinOp::Iff => c1.iff(c2),
482            BinOp::Imp => c1.imp(c2),
483            BinOp::Or => c1.or(c2),
484            BinOp::And => c1.and(c2),
485            BinOp::Gt(Sort::Int) => c1.gt(c2),
486            BinOp::Ge(Sort::Int) => c1.ge(c2),
487            BinOp::Lt(Sort::Int) => c2.gt(c1),
488            BinOp::Le(Sort::Int) => c2.ge(c1),
489            BinOp::Eq => Some(c1.eq(c2)),
490            BinOp::Ne => Some(c1.ne(c2)),
491            _ => None,
492        }
493    }
494
495    /// Simplify the expression by removing double negations, short-circuiting boolean connectives and
496    /// doing constant folding. Note that we also have [`TypeFoldable::normalize`] which applies beta
497    /// reductions for tuples and abstractions.
498    ///
499    /// Additionally replaces any occurrences of elements in assumed_preds with True.
500    pub fn simplify(&self, assumed_preds: &SnapshotMap<Expr, ()>) -> Expr {
501        struct Simplify<'a> {
502            assumed_preds: &'a SnapshotMap<Expr, ()>,
503        }
504
505        impl TypeFolder for Simplify<'_> {
506            fn fold_expr(&mut self, expr: &Expr) -> Expr {
507                if self.assumed_preds.get(&expr.erase_spans()).is_some() {
508                    return Expr::tt();
509                }
510                let span = expr.span();
511                match expr.kind() {
512                    ExprKind::BinaryOp(op, e1, e2) => {
513                        let e1 = e1.fold_with(self);
514                        let e2 = e2.fold_with(self);
515                        match (op, e1.kind(), e2.kind()) {
516                            (BinOp::And, ExprKind::Constant(Constant::Bool(false)), _) => {
517                                Expr::constant(Constant::Bool(false)).at_opt(e1.span())
518                            }
519                            (BinOp::And, _, ExprKind::Constant(Constant::Bool(false))) => {
520                                Expr::constant(Constant::Bool(false)).at_opt(e2.span())
521                            }
522                            (BinOp::And, ExprKind::Constant(Constant::Bool(true)), _) => e2,
523                            (BinOp::And, _, ExprKind::Constant(Constant::Bool(true))) => e1,
524                            (op, ExprKind::Constant(c1), ExprKind::Constant(c2)) => {
525                                if let Some(c) = Expr::const_op(op, c1, c2) {
526                                    Expr::constant(c).at_opt(span.or(e2.span()))
527                                } else {
528                                    Expr::binary_op(op.clone(), e1, e2).at_opt(span)
529                                }
530                            }
531                            _ => Expr::binary_op(op.clone(), e1, e2).at_opt(span),
532                        }
533                    }
534                    ExprKind::UnaryOp(UnOp::Not, e) => {
535                        let e = e.fold_with(self);
536                        match e.kind() {
537                            ExprKind::Constant(Constant::Bool(b)) => {
538                                Expr::constant(Constant::Bool(!b))
539                            }
540                            ExprKind::UnaryOp(UnOp::Not, e) => e.clone(),
541                            ExprKind::BinaryOp(BinOp::Eq, e1, e2) => {
542                                Expr::binary_op(BinOp::Ne, e1, e2).at_opt(span)
543                            }
544                            _ => Expr::unary_op(UnOp::Not, e).at_opt(span),
545                        }
546                    }
547                    ExprKind::IfThenElse(p, e1, e2) => {
548                        let p = p.fold_with(self);
549                        if p.is_trivially_true() {
550                            e1.fold_with(self).at_opt(span)
551                        } else if p.is_trivially_false() {
552                            e2.fold_with(self).at_opt(span)
553                        } else {
554                            Expr::ite(p, e1.fold_with(self), e2.fold_with(self)).at_opt(span)
555                        }
556                    }
557                    _ => expr.super_fold_with(self),
558                }
559            }
560        }
561        self.fold_with(&mut Simplify { assumed_preds })
562    }
563
564    pub fn to_loc(&self) -> Option<Loc> {
565        match self.kind() {
566            ExprKind::Local(local) => Some(Loc::Local(*local)),
567            ExprKind::Var(var) => Some(Loc::Var(*var)),
568            _ => None,
569        }
570    }
571
572    pub fn to_path(&self) -> Option<Path> {
573        let mut expr = self;
574        let mut proj = vec![];
575        while let ExprKind::PathProj(e, field) = expr.kind() {
576            proj.push(*field);
577            expr = e;
578        }
579        proj.reverse();
580        Some(Path::new(expr.to_loc()?, proj))
581    }
582
583    /// Whether this is an aggregate expression with no fields.
584    pub fn is_unit(&self) -> bool {
585        matches!(self.kind(), ExprKind::Tuple(flds) if flds.is_empty())
586            || matches!(self.kind(), ExprKind::Ctor(Ctor::Struct(_), flds) if flds.is_empty())
587    }
588
589    pub fn eta_expand_abs(&self, inputs: &BoundVariableKinds, output: Sort) -> Lambda {
590        let args = (0..inputs.len())
591            .map(|idx| Expr::bvar(INNERMOST, BoundVar::from_usize(idx), BoundReftKind::Anon))
592            .collect();
593        let body = Expr::app(self, List::empty(), args);
594        Lambda::bind_with_vars(body, inputs.clone(), output)
595    }
596
597    /// Applies a field projection to an expression and optimistically try to beta reduce it
598    pub fn proj_and_reduce(&self, proj: FieldProj) -> Expr {
599        match self.kind() {
600            ExprKind::Tuple(flds) | ExprKind::Ctor(Ctor::Struct(_), flds) => {
601                flds[proj.field_idx() as usize].clone()
602            }
603            _ => Expr::field_proj(self.clone(), proj),
604        }
605    }
606
607    pub fn visit_conj<'a>(&'a self, mut f: impl FnMut(&'a Expr)) {
608        fn go<'a>(e: &'a Expr, f: &mut impl FnMut(&'a Expr)) {
609            if let ExprKind::BinaryOp(BinOp::And, e1, e2) = e.kind() {
610                go(e1, f);
611                go(e2, f);
612            } else {
613                f(e);
614            }
615        }
616        go(self, &mut f);
617    }
618
619    pub fn flatten_conjs(&self) -> Vec<&Expr> {
620        let mut vec = vec![];
621        self.visit_conj(|e| vec.push(e));
622        vec
623    }
624
625    pub fn has_evars(&self) -> bool {
626        struct HasEvars;
627
628        impl TypeVisitor for HasEvars {
629            type BreakTy = ();
630            fn visit_expr(&mut self, expr: &Expr) -> ControlFlow<Self::BreakTy> {
631                if let ExprKind::Var(Var::EVar(_)) = expr.kind() {
632                    ControlFlow::Break(())
633                } else {
634                    expr.super_visit_with(self)
635                }
636            }
637        }
638
639        self.visit_with(&mut HasEvars).is_break()
640    }
641
642    pub fn erase_spans(&self) -> Expr {
643        struct SpanEraser;
644        impl TypeFolder for SpanEraser {
645            fn fold_expr(&mut self, e: &Expr) -> Expr {
646                e.super_fold_with(self).at_opt(None)
647            }
648        }
649        self.fold_with(&mut SpanEraser)
650    }
651}
652
653#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Debug)]
654pub struct ESpan {
655    /// The top-level span information
656    pub span: Span,
657    /// The span for the (base) call-site for def-expanded spans
658    pub base: Option<Span>,
659}
660
661impl ESpan {
662    pub fn new(span: Span) -> Self {
663        Self { span, base: None }
664    }
665
666    pub fn with_base(&self, espan: ESpan) -> Self {
667        Self { span: self.span, base: Some(espan.span) }
668    }
669}
670
671#[derive(
672    Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Debug, TypeFoldable, TypeVisitable,
673)]
674pub enum BinOp {
675    Iff,
676    Imp,
677    Or,
678    And,
679    Eq,
680    Ne,
681    Gt(Sort),
682    Ge(Sort),
683    Lt(Sort),
684    Le(Sort),
685    Add(Sort),
686    Sub(Sort),
687    Mul(Sort),
688    Div(Sort),
689    Mod(Sort),
690    BitAnd(Sort),
691    BitOr(Sort),
692    BitXor(Sort),
693    BitShl(Sort),
694    BitShr(Sort),
695}
696
697#[derive(Clone, Copy, PartialEq, Eq, Hash, Encodable, Debug, Decodable)]
698pub enum UnOp {
699    Not,
700    Neg,
701}
702
703#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, TyEncodable, TyDecodable)]
704pub enum Ctor {
705    /// for indices represented as `struct` in the refinement logic (e.g. using `refined_by` annotations)
706    Struct(DefId),
707    /// for indices represented as  `enum` in the refinement logic (e.g. using `reflected` annotations)
708    Enum(DefId, VariantIdx),
709}
710
711impl Ctor {
712    pub fn def_id(&self) -> DefId {
713        match self {
714            Self::Struct(def_id) | Self::Enum(def_id, _) => *def_id,
715        }
716    }
717
718    pub fn variant_idx(&self) -> VariantIdx {
719        match self {
720            Self::Struct(_) => FIRST_VARIANT,
721            Self::Enum(_, variant_idx) => *variant_idx,
722        }
723    }
724
725    fn is_enum(&self) -> bool {
726        matches!(self, Self::Enum(..))
727    }
728}
729
730/// # Primitive Properties
731/// Given a primop `op` with signature `(t1,...,tn) -> t`
732/// We define a refined type for `op` expressed as a `RuleMatcher`
733///
734/// ```text
735/// op :: (x1: t1, ..., xn: tn) -> { t[op_val[op](x1,...,xn)] | op_rel[x1,...,xn] }
736/// ```
737/// That is, using two *uninterpreted functions* `op_val` and `op_rel` that respectively denote
738/// 1. The _value_ of the primop, and
739/// 2. Some invariant _relation_ that holds for the primop.
740///
741/// The latter can be extended by the user via a `property` definition, which allows us
742/// to customize primops like `<<` with extra "facts" or lemmas. See `tests/tests/pos/surface/primops00.rs` for an example.
743#[derive(Debug, Clone, TyEncodable, TyDecodable, PartialEq, Eq, Hash)]
744pub enum InternalFuncKind {
745    /// UIF representing the value of a primop
746    Val(BinOp),
747    /// UIF representing the relationship of a primop
748    Rel(BinOp),
749    // Conversions betweeen Sorts
750    Cast,
751    /// Built-in UIF for pointer size: `RawPtr -> Int`
752    PtrSize,
753}
754
755#[derive(Debug, Clone, TyEncodable, TyDecodable, PartialEq, Eq, Hash)]
756pub enum SpecFuncKind {
757    /// Theory symbols *interpreted* by the SMT solver
758    Thy(liquid_fixpoint::ThyFunc),
759    /// User-defined function. This can be either a function with a body or a UIF.
760    Def(FluxDefId),
761}
762
763#[derive(Clone, PartialEq, Eq, Hash, TyEncodable, Debug, TyDecodable)]
764pub enum ExprKind {
765    Var(Var),
766    Local(Local),
767    Constant(Constant),
768    /// A rust constant. This can be either `DefKind::Const` or `DefKind::AssocConst`
769    ConstDefId(DefId),
770    BinaryOp(BinOp, Expr, Expr),
771    GlobalFunc(SpecFuncKind),
772    InternalFunc(InternalFuncKind),
773    UnaryOp(UnOp, Expr),
774    FieldProj(Expr, FieldProj),
775    /// A variant used in the logic to represent a variant of an ADT as a pair of the `DefId` and variant-index
776    Ctor(Ctor, List<Expr>),
777    Tuple(List<Expr>),
778    PathProj(Expr, FieldIdx),
779    IfThenElse(Expr, Expr, Expr),
780    KVar(KVar),
781    Alias(AliasReft, List<Expr>),
782    Let(Expr, Binder<Expr>),
783    /// Function application. The syntax allows arbitrary expressions in function position, but in
784    /// practice we are restricted by what's possible to encode in fixpoint. In a nutshell, we need
785    /// to make sure that expressions that can't be encoded are eliminated before we generate the
786    /// fixpoint constraint. Most notably, lambda abstractions have to be fully applied before
787    /// encoding into fixpoint (except when they appear as an index at the top-level).
788    App(Expr, List<SortArg>, List<Expr>),
789    /// Lambda abstractions. They are purely syntactic and we don't encode them in the logic. As such,
790    /// they have some syntactic restrictions that we must carefully maintain:
791    ///
792    /// 1. They can appear as an index at the top level.
793    /// 2. We can only substitute an abstraction for a variable in function position (or as an index).
794    ///    More generally, we need to partially evaluate expressions such that all abstractions in
795    ///    non-index position are eliminated before encoding into fixpoint. Right now, the
796    ///    implementation only evaluates abstractions that are immediately applied to arguments,
797    ///    thus the restriction.
798    Abs(Lambda),
799
800    /// Bounded quantifiers `exists i in 0..4 { pred(i) }` and `forall i in 0..4 { pred(i) }`.
801    BoundedQuant(fhir::QuantKind, fhir::Range, Binder<Expr>),
802    /// A hole is an expression that must be inferred either *semantically* by generating a kvar or
803    /// *syntactically* by generating an evar. Whether a hole can be inferred semantically or
804    /// syntactically depends on the position it appears: only holes appearing in predicate position
805    /// can be inferred with a kvar (provided it satisfies the fixpoint horn constraints) and only
806    /// holes used as an index (a position that fully determines their value) can be inferred with
807    /// an evar.
808    ///
809    /// Holes are implicitly defined in a scope, i.e., their solution could mention free and bound
810    /// variables in this scope. This must be considered when generating an inference variables for
811    /// them (either evar or kvar). In fact, the main reason we have holes is that we want to
812    /// decouple the places where we generate holes (where we don't want to worry about the scope),
813    /// and the places where we generate inference variable for them (where we do need to worry
814    /// about the scope).
815    Hole(HoleKind),
816    ForAll(Binder<Expr>),
817    /// Only for non-cuts solutions from fixpoint
818    Exists(Binder<Expr>),
819    /// Is the expression constructed from constructor of the given DefId (which should be `reflected` Enum)
820    IsCtor(DefId, VariantIdx, Expr),
821}
822
823impl ExprKind {
824    fn intern(self) -> Expr {
825        Expr { kind: Interned::new(self), espan: None }
826    }
827}
828
829#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Debug)]
830pub enum AggregateKind {
831    Tuple(usize),
832    Adt(DefId),
833}
834
835#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Debug)]
836pub enum FieldProj {
837    Tuple { arity: usize, field: u32 },
838    Adt { def_id: DefId, field: u32 },
839}
840
841impl FieldProj {
842    pub fn arity(&self, genv: GlobalEnv) -> QueryResult<usize> {
843        match self {
844            FieldProj::Tuple { arity, .. } => Ok(*arity),
845            FieldProj::Adt { def_id, .. } => {
846                Ok(genv.adt_sort_def_of(*def_id)?.struct_variant().fields())
847            }
848        }
849    }
850
851    pub fn field_idx(&self) -> u32 {
852        match self {
853            FieldProj::Tuple { field, .. } | FieldProj::Adt { field, .. } => *field,
854        }
855    }
856}
857
858/// The position where a [hole] appears. This determines how it will be inferred. This is related
859/// to, but not the same as, an [`InferMode`].
860///
861/// [`InferMode`]: super::InferMode
862/// [hole]: ExprKind::Hole
863#[derive(
864    Debug, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, TypeFoldable, TypeVisitable,
865)]
866pub enum HoleKind {
867    /// A hole in predicate position (e.g., the predicate in a [`TyKind::Constr`]). It will be
868    /// inferred by generating a kvar.
869    ///
870    /// [`TyKind::Constr`]: super::TyKind::Constr
871    Pred,
872    /// A hole used as a refinement argument or index. It will be inferred by generating an evar.
873    /// The expression filling the hole must have the provided sort.
874    ///
875    /// NOTE(nilehmann) we used to require the `Sort` for generating the evar because we needed it
876    /// to eta-expand aggregate sorts. We've since removed this behavior but I'm keeping it here
877    /// just in case. We could remove in case it becomes too problematic.
878    Expr(Sort),
879}
880
881/// In theory a kvar is just an unknown predicate that can use some variables in scope. In practice,
882/// fixpoint makes a difference between the first and the rest of the arguments, the first one being
883/// the kvar's *self argument*. Fixpoint will only instantiate qualifiers that use the self argument.
884/// Flux generalizes the self argument to be a list. We call the rest of the arguments the *scope*.
885#[derive(Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, TypeVisitable, TypeFoldable)]
886pub struct KVar {
887    pub kvid: KVid,
888    /// The number of arguments consider to be *self arguments*.
889    pub self_args: usize,
890    /// The list of *all* arguments with the self arguments at the beginning, i.e., the
891    /// list of self arguments followed by the scope.
892    pub args: List<Expr>,
893}
894
895#[derive(Clone, Debug, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Encodable, Decodable)]
896pub struct EarlyReftParam {
897    pub index: u32,
898    pub name: Symbol,
899}
900
901#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Encodable, Decodable, Debug)]
902pub struct BoundReft {
903    pub var: BoundVar,
904    pub kind: BoundReftKind,
905}
906
907#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, TyEncodable, TyDecodable)]
908pub enum Var {
909    Free(Name),
910    Bound(DebruijnIndex, BoundReft),
911    EarlyParam(EarlyReftParam),
912    EVar(EVid),
913    ConstGeneric(ParamConst),
914}
915
916#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord, TyEncodable, TyDecodable)]
917pub struct Path {
918    pub loc: Loc,
919    projection: List<FieldIdx>,
920}
921
922#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, TyEncodable, TyDecodable)]
923pub enum Loc {
924    Local(Local),
925    Var(Var),
926}
927
928newtype_index! {
929    /// *E*xistential *v*ariable *id*
930    #[debug_format = "?{}e"]
931    #[orderable]
932    #[encodable]
933    pub struct EVid {}
934}
935
936newtype_index! {
937    #[debug_format = "$k{}"]
938    #[encodable]
939    pub struct KVid {}
940}
941
942newtype_index! {
943    #[debug_format = "a{}"]
944    #[orderable]
945    #[encodable]
946    pub struct Name {}
947}
948
949#[derive(Copy, Debug, Clone)]
950pub enum NameProvenance {
951    Unknown,
952    UnfoldBoundReft(BoundReftKind),
953}
954
955impl NameProvenance {
956    pub fn opt_symbol(&self) -> Option<Symbol> {
957        match &self {
958            NameProvenance::UnfoldBoundReft(BoundReftKind::Named(name)) => Some(*name),
959            _ => None,
960        }
961    }
962}
963
964#[derive(PartialEq, Eq, Hash, Debug)]
965pub enum PrettyVar<V> {
966    Local(V),
967    Param(EarlyReftParam),
968}
969
970impl<V: Copy + Into<usize>> PrettyVar<V> {
971    pub fn as_subscript(&self) -> String {
972        let idx = match self {
973            PrettyVar::Local(v) => (*v).into(),
974            PrettyVar::Param(p) => p.index as usize,
975        };
976        as_subscript(idx)
977    }
978}
979
980pub struct PrettyMap<V: Eq + Hash> {
981    map: FxHashMap<PrettyVar<V>, String>,
982    count: FxHashMap<Symbol, usize>,
983}
984
985impl<V: Eq + Hash + Copy + Into<usize>> PrettyMap<V> {
986    pub fn new() -> Self {
987        PrettyMap { map: FxHashMap::default(), count: FxHashMap::default() }
988    }
989
990    pub fn set(&mut self, var: PrettyVar<V>, prefix: Option<Symbol>) -> String {
991        // if already defined, return it
992        if let Some(symbol) = self.map.get(&var) {
993            return symbol.clone();
994        }
995        // else define it, and stash
996        let symbol = if let Some(prefix) = prefix {
997            let index = self.count.entry(prefix).or_insert(0);
998            let symbol = format!("{}{}", prefix, as_subscript(*index));
999            *index += 1;
1000            symbol
1001        } else {
1002            format!("a'{}", var.as_subscript())
1003        };
1004        self.map.insert(var, symbol.clone());
1005        symbol
1006    }
1007
1008    pub fn get(&self, key: &PrettyVar<V>) -> String {
1009        match self.map.get(key) {
1010            Some(s) => s.clone(),
1011            None => format!("a'{}", key.as_subscript()),
1012        }
1013    }
1014}
1015
1016impl KVar {
1017    pub fn new(kvid: KVid, self_args: usize, args: Vec<Expr>) -> Self {
1018        KVar { kvid, self_args, args: List::from_vec(args) }
1019    }
1020
1021    fn self_args(&self) -> &[Expr] {
1022        &self.args[..self.self_args]
1023    }
1024
1025    fn scope(&self) -> &[Expr] {
1026        &self.args[self.self_args..]
1027    }
1028}
1029
1030impl Var {
1031    pub fn to_expr(&self) -> Expr {
1032        Expr::var(*self)
1033    }
1034}
1035
1036impl Path {
1037    pub fn new(loc: Loc, projection: impl Into<List<FieldIdx>>) -> Path {
1038        Path { loc, projection: projection.into() }
1039    }
1040
1041    pub fn projection(&self) -> &[FieldIdx] {
1042        &self.projection[..]
1043    }
1044
1045    pub fn to_expr(&self) -> Expr {
1046        self.projection
1047            .iter()
1048            .fold(self.loc.to_expr(), |e, f| Expr::path_proj(e, *f))
1049    }
1050
1051    pub fn to_loc(&self) -> Option<Loc> {
1052        if self.projection.is_empty() { Some(self.loc) } else { None }
1053    }
1054}
1055
1056impl Loc {
1057    pub fn to_expr(&self) -> Expr {
1058        match self {
1059            Loc::Local(local) => Expr::local(*local),
1060            Loc::Var(var) => Expr::var(*var),
1061        }
1062    }
1063}
1064
1065macro_rules! impl_ops {
1066    ($($op:ident: $method:ident),*) => {$(
1067        impl<Rhs> std::ops::$op<Rhs> for Expr
1068        where
1069            Rhs: Into<Expr>,
1070        {
1071            type Output = Expr;
1072
1073            fn $method(self, rhs: Rhs) -> Self::Output {
1074                let sort = crate::rty::Sort::Int;
1075                Expr::binary_op(BinOp::$op(sort), self, rhs)
1076            }
1077        }
1078
1079        impl<Rhs> std::ops::$op<Rhs> for &Expr
1080        where
1081            Rhs: Into<Expr>,
1082        {
1083            type Output = Expr;
1084
1085            fn $method(self, rhs: Rhs) -> Self::Output {
1086                let sort = crate::rty::Sort::Int;
1087                Expr::binary_op(BinOp::$op(sort), self, rhs)
1088            }
1089        }
1090    )*};
1091}
1092impl_ops!(Add: add, Sub: sub, Mul: mul, Div: div);
1093
1094impl From<i32> for Expr {
1095    fn from(value: i32) -> Self {
1096        Expr::constant(Constant::from(value))
1097    }
1098}
1099
1100impl From<&Expr> for Expr {
1101    fn from(e: &Expr) -> Self {
1102        e.clone()
1103    }
1104}
1105
1106impl From<Path> for Expr {
1107    fn from(path: Path) -> Self {
1108        path.to_expr()
1109    }
1110}
1111
1112impl From<Name> for Expr {
1113    fn from(name: Name) -> Self {
1114        Expr::fvar(name)
1115    }
1116}
1117
1118impl From<Var> for Expr {
1119    fn from(var: Var) -> Self {
1120        Expr::var(var)
1121    }
1122}
1123
1124impl From<SpecFuncKind> for Expr {
1125    fn from(kind: SpecFuncKind) -> Self {
1126        Expr::global_func(kind)
1127    }
1128}
1129
1130impl From<InternalFuncKind> for Expr {
1131    fn from(kind: InternalFuncKind) -> Self {
1132        Expr::internal_func(kind)
1133    }
1134}
1135
1136impl From<Loc> for Path {
1137    fn from(loc: Loc) -> Self {
1138        Path::new(loc, vec![])
1139    }
1140}
1141
1142impl From<Name> for Loc {
1143    fn from(name: Name) -> Self {
1144        Loc::Var(Var::Free(name))
1145    }
1146}
1147
1148impl From<Local> for Loc {
1149    fn from(local: Local) -> Self {
1150        Loc::Local(local)
1151    }
1152}
1153
1154#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Encodable, Decodable)]
1155pub struct Real(pub u128);
1156
1157#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Encodable, Decodable)]
1158pub enum Constant {
1159    Int(BigInt),
1160    Real(Real),
1161    Bool(bool),
1162    Str(Symbol),
1163    Char(char),
1164    BitVec(u128, u32),
1165}
1166
1167impl Constant {
1168    pub const ZERO: Constant = Constant::Int(BigInt::ZERO);
1169    pub const ONE: Constant = Constant::Int(BigInt::ONE);
1170    pub const TRUE: Constant = Constant::Bool(true);
1171
1172    fn to_bool(self) -> Option<bool> {
1173        match self {
1174            Constant::Bool(b) => Some(b),
1175            _ => None,
1176        }
1177    }
1178
1179    fn to_int(self) -> Option<BigInt> {
1180        match self {
1181            Constant::Int(n) => Some(n),
1182            _ => None,
1183        }
1184    }
1185
1186    pub fn iff(&self, other: &Constant) -> Option<Constant> {
1187        let b1 = self.to_bool()?;
1188        let b2 = other.to_bool()?;
1189        Some(Constant::Bool(b1 == b2))
1190    }
1191
1192    pub fn imp(&self, other: &Constant) -> Option<Constant> {
1193        let b1 = self.to_bool()?;
1194        let b2 = other.to_bool()?;
1195        Some(Constant::Bool(!b1 || b2))
1196    }
1197
1198    pub fn or(&self, other: &Constant) -> Option<Constant> {
1199        let b1 = self.to_bool()?;
1200        let b2 = other.to_bool()?;
1201        Some(Constant::Bool(b1 || b2))
1202    }
1203
1204    pub fn and(&self, other: &Constant) -> Option<Constant> {
1205        let b1 = self.to_bool()?;
1206        let b2 = other.to_bool()?;
1207        Some(Constant::Bool(b1 && b2))
1208    }
1209
1210    pub fn eq(&self, other: &Constant) -> Constant {
1211        Constant::Bool(*self == *other)
1212    }
1213
1214    pub fn ne(&self, other: &Constant) -> Constant {
1215        Constant::Bool(*self != *other)
1216    }
1217
1218    pub fn gt(&self, other: &Constant) -> Option<Constant> {
1219        let n1 = self.to_int()?;
1220        let n2 = other.to_int()?;
1221        Some(Constant::Bool(n1 > n2))
1222    }
1223
1224    pub fn ge(&self, other: &Constant) -> Option<Constant> {
1225        let n1 = self.to_int()?;
1226        let n2 = other.to_int()?;
1227        Some(Constant::Bool(n1 >= n2))
1228    }
1229
1230    pub fn from_scalar_int<'tcx, T>(tcx: TyCtxt<'tcx>, scalar: ScalarInt, t: &T) -> Option<Self>
1231    where
1232        T: ToRustc<'tcx, T = rustc_middle::ty::Ty<'tcx>>,
1233    {
1234        use rustc_middle::ty::TyKind;
1235        let ty = t.to_rustc(tcx);
1236        match ty.kind() {
1237            TyKind::Int(int_ty) => Some(Constant::from(scalar_to_int(tcx, scalar, *int_ty))),
1238            TyKind::Uint(uint_ty) => Some(Constant::from(scalar_to_uint(tcx, scalar, *uint_ty))),
1239            TyKind::Bool => {
1240                let b = scalar_to_bits(tcx, scalar, ty)?;
1241                Some(Constant::Bool(b != 0))
1242            }
1243            TyKind::Char => {
1244                let b = scalar_to_bits(tcx, scalar, ty)?;
1245                Some(Constant::Char(char::from_u32(b as u32)?))
1246            }
1247            _ => bug!(),
1248        }
1249    }
1250
1251    /// See [`BigInt::int_min`]
1252    pub fn int_min(bit_width: u32) -> Constant {
1253        Constant::Int(BigInt::int_min(bit_width))
1254    }
1255
1256    /// See [`BigInt::int_max`]
1257    pub fn int_max(bit_width: u32) -> Constant {
1258        Constant::Int(BigInt::int_max(bit_width))
1259    }
1260
1261    /// See [`BigInt::uint_max`]
1262    pub fn uint_max(bit_width: u32) -> Constant {
1263        Constant::Int(BigInt::uint_max(bit_width))
1264    }
1265}
1266
1267impl From<i32> for Constant {
1268    fn from(c: i32) -> Self {
1269        Constant::Int(c.into())
1270    }
1271}
1272
1273impl From<usize> for Constant {
1274    fn from(u: usize) -> Self {
1275        Constant::Int(u.into())
1276    }
1277}
1278
1279impl From<u32> for Constant {
1280    fn from(c: u32) -> Self {
1281        Constant::Int(c.into())
1282    }
1283}
1284
1285impl From<u64> for Constant {
1286    fn from(c: u64) -> Self {
1287        Constant::Int(c.into())
1288    }
1289}
1290
1291impl From<u128> for Constant {
1292    fn from(c: u128) -> Self {
1293        Constant::Int(c.into())
1294    }
1295}
1296
1297impl From<i128> for Constant {
1298    fn from(c: i128) -> Self {
1299        Constant::Int(c.into())
1300    }
1301}
1302
1303impl From<bool> for Constant {
1304    fn from(b: bool) -> Self {
1305        Constant::Bool(b)
1306    }
1307}
1308
1309impl From<Symbol> for Constant {
1310    fn from(s: Symbol) -> Self {
1311        Constant::Str(s)
1312    }
1313}
1314
1315impl From<char> for Constant {
1316    fn from(c: char) -> Self {
1317        Constant::Char(c)
1318    }
1319}
1320
1321impl_internable!(ExprKind);
1322impl_slice_internable!(Expr, KVar);
1323
1324#[derive(Debug)]
1325pub struct FieldBind<T> {
1326    pub name: Symbol,
1327    pub value: T,
1328}
1329
1330impl<T: Pretty> Pretty for FieldBind<T> {
1331    fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1332        w!(cx, f, "{}: {:?}", ^self.name, &self.value)
1333    }
1334}
1335
1336pub(crate) mod pretty {
1337
1338    use flux_rustc_bridge::def_id_to_string;
1339
1340    use super::*;
1341    use crate::name_of_thy_func;
1342
1343    #[derive(PartialEq, Eq, PartialOrd, Ord)]
1344    enum Precedence {
1345        Iff,
1346        Imp,
1347        Or,
1348        And,
1349        Cmp,
1350        Bitvec,
1351        AddSub,
1352        MulDiv,
1353    }
1354
1355    impl BinOp {
1356        fn precedence(&self) -> Precedence {
1357            match self {
1358                BinOp::Iff => Precedence::Iff,
1359                BinOp::Imp => Precedence::Imp,
1360                BinOp::Or => Precedence::Or,
1361                BinOp::And => Precedence::And,
1362                BinOp::Eq
1363                | BinOp::Ne
1364                | BinOp::Gt(_)
1365                | BinOp::Lt(_)
1366                | BinOp::Ge(_)
1367                | BinOp::Le(_) => Precedence::Cmp,
1368                BinOp::Add(_) | BinOp::Sub(_) => Precedence::AddSub,
1369                BinOp::Mul(_) | BinOp::Div(_) | BinOp::Mod(_) => Precedence::MulDiv,
1370                BinOp::BitAnd(_)
1371                | BinOp::BitOr(_)
1372                | BinOp::BitShl(_)
1373                | BinOp::BitShr(_)
1374                | BinOp::BitXor(_) => Precedence::Bitvec,
1375            }
1376        }
1377    }
1378
1379    impl Precedence {
1380        pub fn is_associative(&self) -> bool {
1381            !matches!(self, Precedence::Imp | Precedence::Cmp)
1382        }
1383    }
1384
1385    pub fn should_parenthesize(op: &BinOp, child: &Expr) -> bool {
1386        if let ExprKind::BinaryOp(child_op, ..) = child.kind() {
1387            child_op.precedence() < op.precedence()
1388                || (child_op.precedence() == op.precedence() && !op.precedence().is_associative())
1389        } else {
1390            false
1391        }
1392    }
1393
1394    impl Pretty for Ctor {
1395        fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1396            match self {
1397                Ctor::Struct(def_id) => {
1398                    w!(cx, f, "{:?}", def_id)
1399                }
1400                Ctor::Enum(def_id, variant_idx) => {
1401                    w!(cx, f, "{:?}::{:?}", def_id, ^variant_idx)
1402                }
1403            }
1404        }
1405    }
1406
1407    impl Pretty for fhir::QuantKind {
1408        fn fmt(&self, _cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1409            match self {
1410                fhir::QuantKind::Exists => w!(cx, f, "∃"),
1411                fhir::QuantKind::Forall => w!(cx, f, "∀"),
1412            }
1413        }
1414    }
1415
1416    impl Pretty for InternalFuncKind {
1417        fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1418            match self {
1419                InternalFuncKind::Val(op) => w!(cx, f, "[{:?}]", op),
1420                InternalFuncKind::Rel(op) => w!(cx, f, "[{:?}]?", op),
1421                InternalFuncKind::Cast => w!(cx, f, "cast"),
1422                InternalFuncKind::PtrSize => w!(cx, f, "ptr_size"),
1423            }
1424        }
1425    }
1426
1427    impl Pretty for Expr {
1428        fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1429            let e = if cx.simplify_exprs {
1430                self.simplify(&SnapshotMap::default())
1431            } else {
1432                self.clone()
1433            };
1434            match e.kind() {
1435                ExprKind::Var(var) => w!(cx, f, "{:?}", var),
1436                ExprKind::Local(local) => w!(cx, f, "{:?}", ^local),
1437                ExprKind::ConstDefId(did) => w!(cx, f, "{}", ^def_id_to_string(*did)),
1438                ExprKind::Constant(c) => w!(cx, f, "{:?}", c),
1439
1440                ExprKind::BinaryOp(op, e1, e2) => {
1441                    if should_parenthesize(op, e1) {
1442                        w!(cx, f, "({:?})", e1)?;
1443                    } else {
1444                        w!(cx, f, "{:?}", e1)?;
1445                    }
1446                    if matches!(op, BinOp::Div(_)) {
1447                        w!(cx, f, "{:?}", op)?;
1448                    } else {
1449                        w!(cx, f, " {:?} ", op)?;
1450                    }
1451                    if should_parenthesize(op, e2) {
1452                        w!(cx, f, "({:?})", e2)?;
1453                    } else {
1454                        w!(cx, f, "{:?}", e2)?;
1455                    }
1456                    Ok(())
1457                }
1458                ExprKind::UnaryOp(op, e) => {
1459                    if e.is_atom() {
1460                        w!(cx, f, "{:?}{:?}", op, e)
1461                    } else {
1462                        w!(cx, f, "{:?}({:?})", op, e)
1463                    }
1464                }
1465                ExprKind::FieldProj(e, proj) if let ExprKind::Ctor(_, _) = e.kind() => {
1466                    // special case to avoid printing `{n:12}.n` as `12.n` but instead, just print `12`
1467                    // TODO: maintain an invariant that `FieldProj` never has a Ctor as first argument (as always reduced)
1468                    w!(cx, f, "{:?}", e.proj_and_reduce(*proj))
1469                }
1470                ExprKind::FieldProj(e, proj) => {
1471                    if e.is_atom() {
1472                        w!(cx, f, "{:?}.{}", e, ^fmt_field_proj(cx, *proj))
1473                    } else {
1474                        w!(cx, f, "({:?}).{}", e, ^fmt_field_proj(cx, *proj))
1475                    }
1476                }
1477                ExprKind::Tuple(flds) => {
1478                    if let [e] = &flds[..] {
1479                        w!(cx, f, "({:?},)", e)
1480                    } else {
1481                        w!(cx, f, "({:?})", join!(", ", flds))
1482                    }
1483                }
1484                ExprKind::IsCtor(def_id, variant_idx, idx) => {
1485                    w!(cx, f, "({:?} is {:?}::{:?})", idx, def_id, ^variant_idx)
1486                }
1487                ExprKind::Ctor(ctor, flds) => {
1488                    let def_id = ctor.def_id();
1489                    if let Some(adt_sort_def) = cx.adt_sort_def_of(def_id) {
1490                        let variant = adt_sort_def.variant(ctor.variant_idx()).field_names();
1491                        let fields = iter::zip(variant, flds)
1492                            .map(|(name, value)| FieldBind { name: *name, value: value.clone() })
1493                            .collect_vec();
1494                        match ctor {
1495                            Ctor::Struct(_) => {
1496                                w!(cx, f, "{:?} {{ {:?} }}", def_id, join!(", ", fields))
1497                            }
1498                            Ctor::Enum(_, idx) => {
1499                                if fields.is_empty() {
1500                                    w!(cx, f, "{:?}::{:?}", def_id, ^idx.index())
1501                                } else {
1502                                    w!(cx, f, "{:?}::{:?}({:?})", def_id, ^idx.index(), join!(", ", fields))
1503                                }
1504                            }
1505                        }
1506                    } else {
1507                        match ctor {
1508                            Ctor::Struct(_) => {
1509                                w!(cx, f, "{:?} {{ {:?} }}", def_id, join!(", ", flds))
1510                            }
1511                            Ctor::Enum(_, idx) => {
1512                                w!(cx, f, "{:?}::{:?} {{ {:?} }}", def_id, ^idx, join!(", ", flds))
1513                            }
1514                        }
1515                    }
1516                }
1517                ExprKind::PathProj(e, field) => {
1518                    if e.is_atom() {
1519                        w!(cx, f, "{:?}.{:?}", e, field)
1520                    } else {
1521                        w!(cx, f, "({:?}).{:?}", e, field)
1522                    }
1523                }
1524                ExprKind::App(func, _, args) => {
1525                    w!(cx, f, "{:?}({})",
1526                        parens!(func, !func.is_atom()),
1527                        ^args
1528                            .iter()
1529                            .format_with(", ", |arg, f| f(&format_args_cx!(cx, "{:?}", arg)))
1530                    )
1531                }
1532                ExprKind::IfThenElse(p, e1, e2) => {
1533                    w!(cx, f, "if {:?} {{ {:?} }} else {{ {:?} }}", p, e1, e2)
1534                }
1535                ExprKind::Hole(_) => {
1536                    w!(cx, f, "*")
1537                }
1538                ExprKind::KVar(kvar) => {
1539                    w!(cx, f, "{:?}", kvar)
1540                }
1541                ExprKind::Alias(alias, args) => {
1542                    w!(cx, f, "{:?}({:?})", alias, join!(", ", args))
1543                }
1544                ExprKind::Abs(lam) => {
1545                    w!(cx, f, "{:?}", lam)
1546                }
1547                ExprKind::GlobalFunc(SpecFuncKind::Def(did)) => {
1548                    w!(cx, f, "{}", ^did.name())
1549                }
1550                ExprKind::GlobalFunc(SpecFuncKind::Thy(itf)) => {
1551                    if let Some(name) = name_of_thy_func(*itf) {
1552                        w!(cx, f, "{}", ^name)
1553                    } else {
1554                        w!(cx, f, "<error>")
1555                    }
1556                }
1557                ExprKind::InternalFunc(func) => {
1558                    w!(cx, f, "{:?}", func)
1559                }
1560                ExprKind::ForAll(expr) => {
1561                    let vars = expr.vars();
1562                    cx.with_bound_vars(vars, || {
1563                        if !vars.is_empty() {
1564                            cx.fmt_bound_vars(false, "∀", vars, ". ", f)?;
1565                        }
1566                        w!(cx, f, "{:?}", expr.skip_binder_ref())
1567                    })
1568                }
1569                ExprKind::Exists(expr) => {
1570                    let vars = expr.vars();
1571                    cx.with_bound_vars(vars, || {
1572                        if !vars.is_empty() {
1573                            cx.fmt_bound_vars(false, "∃", vars, ". ", f)?;
1574                        }
1575                        w!(cx, f, "{:?}", expr.skip_binder_ref())
1576                    })
1577                }
1578                ExprKind::BoundedQuant(kind, rng, body) => {
1579                    let vars = body.vars();
1580                    cx.with_bound_vars(vars, || {
1581                        w!(
1582                            cx,
1583                            f,
1584                            "{:?} {}..{} {{ {:?} }}",
1585                            kind,
1586                            ^rng.start,
1587                            ^rng.end,
1588                            body.skip_binder_ref()
1589                        )
1590                    })
1591                }
1592                ExprKind::Let(init, body) => {
1593                    let vars = body.vars();
1594                    cx.with_bound_vars(vars, || {
1595                        cx.fmt_bound_vars(false, "(let ", vars, " = ", f)?;
1596                        w!(cx, f, "{:?} in {:?})", init, body.skip_binder_ref())
1597                    })
1598                }
1599            }
1600        }
1601    }
1602
1603    fn fmt_field_proj(cx: &PrettyCx, proj: FieldProj) -> String {
1604        if let FieldProj::Adt { def_id, field } = proj
1605            && let Some(adt_sort_def) = cx.adt_sort_def_of(def_id)
1606        {
1607            format!("{}", adt_sort_def.struct_variant().field_names()[field as usize])
1608        } else {
1609            format!("{}", proj.field_idx())
1610        }
1611    }
1612
1613    impl Pretty for Constant {
1614        fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1615            match self {
1616                Constant::Int(i) => w!(cx, f, "{i}"),
1617                Constant::BitVec(i, sz) => w!(cx, f, "bv({i}, {sz})"),
1618                Constant::Real(r) => w!(cx, f, "{}.0", ^r.0),
1619                Constant::Bool(b) => w!(cx, f, "{b}"),
1620                Constant::Str(sym) => w!(cx, f, "\"{sym}\""),
1621                Constant::Char(c) => w!(cx, f, "\'{c}\'"),
1622            }
1623        }
1624    }
1625
1626    impl Pretty for AliasReft {
1627        fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1628            w!(cx, f, "<({:?}) as {:?}", &self.args[0], self.assoc_id.parent())?;
1629            let args = &self.args[1..];
1630            if !args.is_empty() {
1631                w!(cx, f, "<{:?}>", join!(", ", args))?;
1632            }
1633            w!(cx, f, ">::{}", ^self.assoc_id.name())
1634        }
1635    }
1636
1637    impl Pretty for Lambda {
1638        fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1639            let vars = self.body.vars();
1640            // TODO: remove redundant vars; see Ty
1641            // let redundant_bvars = self.body.redundant_bvars().into_iter().collect();
1642            cx.with_bound_vars(vars, || {
1643                cx.fmt_bound_vars(false, "λ", vars, ". ", f)?;
1644                w!(cx, f, "{:?}", self.body.as_ref().skip_binder())
1645            })
1646        }
1647    }
1648
1649    impl Pretty for Var {
1650        fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1651            match self {
1652                Var::Bound(debruijn, var) => cx.fmt_bound_reft(*debruijn, *var, f),
1653                Var::EarlyParam(var) => w!(cx, f, "{}", ^var.name),
1654                Var::Free(name) => w!(cx, f, "{:?}", ^name),
1655                Var::EVar(evar) => w!(cx, f, "{:?}", ^evar),
1656                Var::ConstGeneric(param) => w!(cx, f, "{}", ^param.name),
1657            }
1658        }
1659    }
1660
1661    impl Pretty for KVar {
1662        fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1663            w!(cx, f, "{:?}", ^self.kvid)?;
1664            match cx.kvar_args {
1665                KVarArgs::All => {
1666                    w!(
1667                        cx,
1668                        f,
1669                        "({:?})[{:?}]",
1670                        join!(", ", self.self_args()),
1671                        join!(", ", self.scope())
1672                    )?;
1673                }
1674                KVarArgs::SelfOnly => w!(cx, f, "({:?})", join!(", ", self.self_args()))?,
1675                KVarArgs::Hide => {}
1676            }
1677            Ok(())
1678        }
1679    }
1680
1681    impl Pretty for Path {
1682        fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1683            w!(cx, f, "{:?}", &self.loc)?;
1684            for field in &self.projection {
1685                w!(cx, f, ".{}", ^u32::from(*field))?;
1686            }
1687            Ok(())
1688        }
1689    }
1690
1691    impl Pretty for Loc {
1692        fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1693            match self {
1694                Loc::Local(local) => w!(cx, f, "{:?}", ^local),
1695                Loc::Var(var) => w!(cx, f, "{:?}", var),
1696            }
1697        }
1698    }
1699
1700    impl Pretty for BinOp {
1701        fn fmt(&self, _cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1702            match self {
1703                BinOp::Iff => w!(cx, f, "⇔"),
1704                BinOp::Imp => w!(cx, f, "⇒"),
1705                BinOp::Or => w!(cx, f, "∨"),
1706                BinOp::And => w!(cx, f, "∧"),
1707                BinOp::Eq => w!(cx, f, "="),
1708                BinOp::Ne => w!(cx, f, "≠"),
1709                BinOp::Gt(_) => w!(cx, f, ">"),
1710                BinOp::Ge(_) => w!(cx, f, "≥"),
1711                BinOp::Lt(_) => w!(cx, f, "<"),
1712                BinOp::Le(_) => w!(cx, f, "≤"),
1713                BinOp::Add(_) => w!(cx, f, "+"),
1714                BinOp::Sub(_) => w!(cx, f, "-"),
1715                BinOp::Mul(_) => w!(cx, f, "*"),
1716                BinOp::Div(_) => w!(cx, f, "/"),
1717                BinOp::Mod(_) => w!(cx, f, "mod"),
1718                BinOp::BitAnd(_) => w!(cx, f, "&"),
1719                BinOp::BitOr(_) => w!(cx, f, "|"),
1720                BinOp::BitXor(_) => w!(cx, f, "^"),
1721                BinOp::BitShl(_) => w!(cx, f, "<<"),
1722                BinOp::BitShr(_) => w!(cx, f, ">>"),
1723            }
1724        }
1725    }
1726
1727    impl Pretty for UnOp {
1728        fn fmt(&self, _cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1729            match self {
1730                UnOp::Not => w!(cx, f, "¬"),
1731                UnOp::Neg => w!(cx, f, "-"),
1732            }
1733        }
1734    }
1735
1736    impl_debug_with_default_cx!(Expr, Loc, Path, Var, KVar, Lambda, AliasReft);
1737
1738    impl PrettyNested for Lambda {
1739        fn fmt_nested(&self, cx: &PrettyCx) -> Result<NestedString, fmt::Error> {
1740            // TODO: remove redundant vars; see Ty
1741            cx.nested_with_bound_vars("λ", self.body.vars(), None, |prefix| {
1742                let expr_d = self.body.skip_binder_ref().fmt_nested(cx)?;
1743                let text = format!("{}{}", prefix, expr_d.text);
1744                Ok(NestedString { text, children: expr_d.children, key: None })
1745            })
1746        }
1747    }
1748
1749    pub fn aggregate_nested(
1750        cx: &PrettyCx,
1751        ctor: &Ctor,
1752        flds: &[Expr],
1753        is_named: bool,
1754    ) -> Result<NestedString, fmt::Error> {
1755        let def_id = ctor.def_id();
1756        let mut text =
1757            if is_named && ctor.is_enum() { format_cx!(cx, "{:?}", ctor) } else { "".to_string() };
1758        if flds.is_empty() {
1759            // No fields, no index
1760            Ok(NestedString { text, children: None, key: None })
1761        } else if flds.len() == 1 {
1762            // Single field, inline index
1763            text += &flds[0].fmt_nested(cx)?.text;
1764            Ok(NestedString { text, children: None, key: None })
1765        } else {
1766            let keys = if let Some(adt_sort_def) = cx.adt_sort_def_of(def_id) {
1767                adt_sort_def
1768                    .variant(ctor.variant_idx())
1769                    .field_names()
1770                    .iter()
1771                    .map(|name| format!("{name}"))
1772                    .collect_vec()
1773            } else {
1774                (0..flds.len()).map(|i| format!("arg{i}")).collect_vec()
1775            };
1776            // Multiple fields, nested index
1777            text += "{..}";
1778            let mut children = vec![];
1779            for (key, fld) in iter::zip(keys, flds) {
1780                let fld_d = fld.fmt_nested(cx)?;
1781                children.push(NestedString { key: Some(key), ..fld_d });
1782            }
1783            Ok(NestedString { text, children: Some(children), key: None })
1784        }
1785    }
1786
1787    impl PrettyNested for Name {
1788        fn fmt_nested(&self, cx: &PrettyCx) -> Result<NestedString, fmt::Error> {
1789            let text = cx.pretty_var_env.get(&PrettyVar::Local(*self));
1790            Ok(NestedString { text, key: None, children: None })
1791        }
1792    }
1793
1794    impl PrettyNested for Expr {
1795        fn fmt_nested(&self, cx: &PrettyCx) -> Result<NestedString, fmt::Error> {
1796            let e = if cx.simplify_exprs {
1797                self.simplify(&SnapshotMap::default())
1798            } else {
1799                self.clone()
1800            };
1801            match e.kind() {
1802                ExprKind::Var(Var::Free(name)) => name.fmt_nested(cx),
1803                ExprKind::Var(..)
1804                | ExprKind::Local(..)
1805                | ExprKind::Constant(..)
1806                | ExprKind::ConstDefId(..)
1807                | ExprKind::Hole(..)
1808                | ExprKind::GlobalFunc(..)
1809                | ExprKind::InternalFunc(..) => debug_nested(cx, &e),
1810                ExprKind::KVar(kvar) => {
1811                    let kv = format!("{:?}", kvar.kvid);
1812                    let mut strs = vec![kv];
1813                    for arg in &kvar.args {
1814                        strs.push(arg.fmt_nested(cx)?.text);
1815                    }
1816                    let text = format!("##[{}]##", strs.join("##"));
1817                    Ok(NestedString { text, children: None, key: None })
1818                }
1819                ExprKind::IfThenElse(p, e1, e2) => {
1820                    let p_d = p.fmt_nested(cx)?;
1821                    let e1_d = e1.fmt_nested(cx)?;
1822                    let e2_d = e2.fmt_nested(cx)?;
1823                    let text = format!("(if {} then {} else {})", p_d.text, e1_d.text, e2_d.text);
1824                    let children = float_children(vec![p_d.children, e1_d.children, e2_d.children]);
1825                    Ok(NestedString { text, children, key: None })
1826                }
1827                ExprKind::BinaryOp(op, e1, e2) => {
1828                    let e1_d = e1.fmt_nested(cx)?;
1829                    let e2_d = e2.fmt_nested(cx)?;
1830                    let e1_text = if should_parenthesize(op, e1) {
1831                        format!("({})", e1_d.text)
1832                    } else {
1833                        e1_d.text
1834                    };
1835                    let e2_text = if should_parenthesize(op, e2) {
1836                        format!("({})", e2_d.text)
1837                    } else {
1838                        e2_d.text
1839                    };
1840                    let op_d = debug_nested(cx, op)?;
1841                    let op_text = if matches!(op, BinOp::Div(_)) {
1842                        op_d.text
1843                    } else {
1844                        format!(" {} ", op_d.text)
1845                    };
1846                    let text = format!("{e1_text}{op_text}{e2_text}");
1847                    let children = float_children(vec![e1_d.children, e2_d.children]);
1848                    Ok(NestedString { text, children, key: None })
1849                }
1850                ExprKind::UnaryOp(op, e) => {
1851                    let e_d = e.fmt_nested(cx)?;
1852                    let op_d = debug_nested(cx, op)?;
1853                    let text = if e.is_atom() {
1854                        format!("{}{}", op_d.text, e_d.text)
1855                    } else {
1856                        format!("{}({})", op_d.text, e_d.text)
1857                    };
1858                    Ok(NestedString { text, children: e_d.children, key: None })
1859                }
1860                ExprKind::FieldProj(e, proj) if let ExprKind::Ctor(_, _) = e.kind() => {
1861                    // special case to avoid printing `{n:12}.n` as `12.n` but instead, just print `12`
1862                    // TODO: maintain an invariant that `FieldProj` never has a Ctor as first argument (as always reduced)
1863                    e.proj_and_reduce(*proj).fmt_nested(cx)
1864                }
1865                ExprKind::FieldProj(e, proj) => {
1866                    let e_d = e.fmt_nested(cx)?;
1867                    let text = if e.is_atom() {
1868                        format!("{}.{}", e_d.text, fmt_field_proj(cx, *proj))
1869                    } else {
1870                        format!("({}).{}", e_d.text, fmt_field_proj(cx, *proj))
1871                    };
1872                    Ok(NestedString { text, children: e_d.children, key: None })
1873                }
1874                ExprKind::Tuple(flds) => {
1875                    let mut texts = vec![];
1876                    let mut kidss = vec![];
1877                    for e in flds {
1878                        let e_d = e.fmt_nested(cx)?;
1879                        texts.push(e_d.text);
1880                        kidss.push(e_d.children);
1881                    }
1882                    let text = if let [e] = &texts[..] {
1883                        format!("({e},)")
1884                    } else {
1885                        format!("({})", texts.join(", "))
1886                    };
1887                    let children = float_children(kidss);
1888                    Ok(NestedString { text, children, key: None })
1889                }
1890                ExprKind::Ctor(ctor, flds) => aggregate_nested(cx, ctor, flds, true),
1891                ExprKind::IsCtor(def_id, variant_idx, idx) => {
1892                    let text = format!("is::{:?}::{:?}( {:?} )", def_id, variant_idx, idx);
1893                    Ok(NestedString { text, children: None, key: None })
1894                }
1895                ExprKind::PathProj(e, field) => {
1896                    let e_d = e.fmt_nested(cx)?;
1897                    let text = if e.is_atom() {
1898                        format!("{}.{:?}", e_d.text, field)
1899                    } else {
1900                        format!("({}).{:?}", e_d.text, field)
1901                    };
1902                    Ok(NestedString { text, children: e_d.children, key: None })
1903                }
1904                ExprKind::Alias(alias, args) => {
1905                    let mut texts = vec![];
1906                    let mut kidss = vec![];
1907                    for arg in args {
1908                        let arg_d = arg.fmt_nested(cx)?;
1909                        texts.push(arg_d.text);
1910                        kidss.push(arg_d.children);
1911                    }
1912                    let text = format_cx!(cx, "{:?}({:?})", alias, texts.join(", "));
1913                    let children = float_children(kidss);
1914                    Ok(NestedString { text, children, key: None })
1915                }
1916                ExprKind::App(func, _, args) => {
1917                    let func_d = func.fmt_nested(cx)?;
1918                    let mut texts = vec![];
1919                    let mut kidss = vec![func_d.children];
1920                    for arg in args {
1921                        let arg_d = arg.fmt_nested(cx)?;
1922                        texts.push(arg_d.text);
1923                        kidss.push(arg_d.children);
1924                    }
1925                    let text = if func.is_atom() {
1926                        format!("{}({})", func_d.text, texts.join(", "))
1927                    } else {
1928                        format!("({})({})", func_d.text, texts.join(", "))
1929                    };
1930                    let children = float_children(kidss);
1931                    Ok(NestedString { text, children, key: None })
1932                }
1933                ExprKind::Abs(lambda) => lambda.fmt_nested(cx),
1934                ExprKind::Let(init, body) => {
1935                    // FIXME this is very wrong!
1936                    cx.nested_with_bound_vars("let", body.vars(), None, |prefix| {
1937                        let body = body.skip_binder_ref().fmt_nested(cx)?;
1938                        let text = format!("{:?} {}{}", init, prefix, body.text);
1939                        Ok(NestedString { text, children: body.children, key: None })
1940                    })
1941                }
1942                ExprKind::BoundedQuant(kind, rng, body) => {
1943                    let left = match kind {
1944                        fhir::QuantKind::Forall => "∀",
1945                        fhir::QuantKind::Exists => "∃",
1946                    };
1947                    let right = Some(format!(" in {}..{}", rng.start, rng.end));
1948
1949                    cx.nested_with_bound_vars(left, body.vars(), right, |all_str| {
1950                        let expr_d = body.as_ref().skip_binder().fmt_nested(cx)?;
1951                        let text = format!("{}{}", all_str, expr_d.text);
1952                        Ok(NestedString { text, children: expr_d.children, key: None })
1953                    })
1954                }
1955                ExprKind::ForAll(expr) => {
1956                    cx.nested_with_bound_vars("∀", expr.vars(), None, |all_str| {
1957                        let expr_d = expr.as_ref().skip_binder().fmt_nested(cx)?;
1958                        let text = format!("{}{}", all_str, expr_d.text);
1959                        Ok(NestedString { text, children: expr_d.children, key: None })
1960                    })
1961                }
1962                ExprKind::Exists(expr) => {
1963                    cx.nested_with_bound_vars("∀", expr.vars(), None, |all_str| {
1964                        let expr_d = expr.as_ref().skip_binder().fmt_nested(cx)?;
1965                        let text = format!("{}{}", all_str, expr_d.text);
1966                        Ok(NestedString { text, children: expr_d.children, key: None })
1967                    })
1968                }
1969            }
1970        }
1971    }
1972}