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