flux_middle/rty/
pretty.rs

1use std::{
2    fmt::{self, Write},
3    iter,
4};
5
6use expr::{FieldBind, pretty::aggregate_nested};
7use rustc_data_structures::snapshot_map::SnapshotMap;
8use rustc_type_ir::DebruijnIndex;
9use ty::{UnevaluatedConst, ValTree, region_to_string};
10
11use super::{fold::TypeVisitable, *};
12use crate::pretty::*;
13
14impl Pretty for ClauseKind {
15    fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
16        match self {
17            ClauseKind::Trait(pred) => w!(cx, f, "Trait ({:?})", ^pred),
18            ClauseKind::Projection(pred) => w!(cx, f, "Projection ({:?})", ^pred),
19            ClauseKind::RegionOutlives(pred) => {
20                w!(cx, f, "Outlives ({:?}, {:?})", &pred.0, &pred.1)
21            }
22            ClauseKind::TypeOutlives(pred) => w!(cx, f, "Outlives ({:?}, {:?})", &pred.0, &pred.1),
23            ClauseKind::ConstArgHasType(c, ty) => w!(cx, f, "ConstArgHasType ({:?}, {:?})", c, ty),
24            ClauseKind::UnstableFeature(_) => w!(cx, f, "UnstableFeature (..)"),
25        }
26    }
27}
28
29impl Pretty for BoundRegionKind {
30    fn fmt(&self, _cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
31        match self {
32            BoundRegionKind::Anon => w!(cx, f, "'<annon>"),
33            BoundRegionKind::NamedAnon(sym) => w!(cx, f, "'{sym}"),
34            BoundRegionKind::Named(def_id) => w!(cx, f, "'{def_id:?}"),
35            BoundRegionKind::ClosureEnv => w!(cx, f, "'<env>"),
36        }
37    }
38}
39
40impl<T> Pretty for Binder<T>
41where
42    T: Pretty,
43{
44    default fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
45        cx.with_bound_vars(self.vars(), || {
46            if !self.vars().is_empty() {
47                cx.fmt_bound_vars(true, "for<", self.vars(), "> ", f)?;
48            }
49            w!(cx, f, "{:?}", self.skip_binder_ref())
50        })
51    }
52}
53
54impl<T: Pretty> std::fmt::Debug for Binder<T> {
55    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
56        pprint_with_default_cx(f, self, None)
57    }
58}
59
60fn format_fn_root_binder<T: Pretty + TypeVisitable>(
61    binder: &Binder<T>,
62    cx: &PrettyCx,
63    fn_root_layer_type: FnRootLayerType,
64    binder_name: &str,
65    f: &mut fmt::Formatter<'_>,
66) -> fmt::Result {
67    let vars = binder.vars();
68    let redundant_bvars = binder.skip_binder_ref().redundant_bvars();
69
70    cx.with_bound_vars_removable(vars, redundant_bvars, Some(fn_root_layer_type), || {
71        // First format the body, adding a dectorator (@ or #) to vars in indexes that we can.
72        let body = format_cx!(cx, "{:?}", binder.skip_binder_ref());
73
74        // Then remove any vars that we added a decorator to.
75        //
76        // As well as any vars that we are removing because they are redundant.
77        let filtered_vars = cx.bvar_env.peek_layer().unwrap().filter_vars(vars);
78        if filtered_vars.is_empty() {
79            write!(f, "{}", body)
80        } else {
81            let left = format!("{binder_name}<");
82            let right = format!("> {}", body);
83            cx.fmt_bound_vars(true, &left, &filtered_vars, &right, f)
84        }
85    })
86}
87
88impl<T: Pretty> Pretty for EarlyBinder<T> {
89    fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
90        cx.with_early_params(|| self.skip_binder_ref().fmt(cx, f))
91    }
92}
93
94impl Pretty for PolyFnSig {
95    fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
96        format_fn_root_binder(self, cx, FnRootLayerType::FnArgs, "for", f)
97    }
98}
99
100impl Pretty for SortCtor {
101    fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
102        match self {
103            SortCtor::Set => w!(cx, f, "Set"),
104            SortCtor::Map => w!(cx, f, "Map"),
105            SortCtor::User(def_id) => w!(cx, f, "{}", ^def_id.name()),
106            SortCtor::Adt(adt_sort_def) => {
107                w!(cx, f, "{:?}", adt_sort_def.did())
108            }
109        }
110    }
111}
112
113impl Pretty for Sort {
114    fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
115        match self {
116            Sort::Bool => w!(cx, f, "bool"),
117            Sort::Int => w!(cx, f, "int"),
118            Sort::Real => w!(cx, f, "real"),
119            Sort::Str => w!(cx, f, "str"),
120            Sort::Char => w!(cx, f, "char"),
121            Sort::BitVec(size) => w!(cx, f, "bitvec<{:?}>", size),
122            Sort::Loc => w!(cx, f, "loc"),
123            Sort::Var(n) => w!(cx, f, "@{}", ^n.index()),
124            Sort::Func(sort) => w!(cx, f, "{:?}", sort),
125            Sort::Tuple(sorts) => {
126                if let [sort] = &sorts[..] {
127                    w!(cx, f, "({:?},)", sort)
128                } else {
129                    w!(cx, f, "({:?})", join!(", ", sorts))
130                }
131            }
132            Sort::Alias(kind, alias_ty) => {
133                fmt_alias_ty(cx, f, *kind, alias_ty)?;
134                w!(cx, f, "::sort")
135            }
136            Sort::App(ctor, sorts) => {
137                if sorts.is_empty() {
138                    w!(cx, f, "{:?}", ctor)
139                } else {
140                    w!(cx, f, "{:?}<{:?}>", ctor, join!(", ", sorts))
141                }
142            }
143            Sort::Param(param_ty) => w!(cx, f, "{}::sort", ^param_ty),
144            Sort::Infer(svar) => w!(cx, f, "{:?}", ^svar),
145            Sort::RawPtr => w!(cx, f, "ptr"),
146            Sort::Err => w!(cx, f, "err"),
147        }
148    }
149
150    fn default_cx(tcx: TyCtxt) -> PrettyCx {
151        PrettyCx::default(tcx).hide_refinements(true)
152    }
153}
154
155impl Pretty for SortArg {
156    fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
157        match self {
158            SortArg::Sort(sort) => w!(cx, f, "{:?}", sort),
159            SortArg::BvSize(size) => w!(cx, f, "{:?}", size),
160        }
161    }
162}
163
164impl Pretty for BvSize {
165    fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
166        match self {
167            BvSize::Fixed(size) => w!(cx, f, "{}", ^size),
168            BvSize::Param(param) => w!(cx, f, "{:?}", ^param),
169            BvSize::Infer(size_vid) => w!(cx, f, "{:?}", ^size_vid),
170        }
171    }
172}
173
174impl Pretty for FuncSort {
175    fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
176        match self.inputs() {
177            [input] => {
178                w!(cx, f, "{:?} -> {:?}", input, self.output())
179            }
180            inputs => {
181                w!(cx, f,
182                   "({}) -> {:?}",
183                   ^inputs
184                       .iter()
185                       .format_with(", ", |s, f| f(&format_args_cx!(cx, "{:?}", s))),
186                   self.output()
187                )
188            }
189        }
190    }
191}
192
193impl Pretty for PolyFuncSort {
194    fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
195        if self.params.is_empty() {
196            w!(cx, f, "{:?}", &self.fsort)
197        } else {
198            w!(cx, f, "for<{}> {:?}", ^self.params.len(), &self.fsort)
199        }
200    }
201}
202
203impl Pretty for FnSig {
204    fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
205        w!(
206            cx,
207            f,
208            "fn({:?}) -> {:?}",
209            join!(", ", self.inputs.iter().map(|input| input.shallow_canonicalize())),
210            &self.output
211        )?;
212        if !self.requires.is_empty() {
213            w!(cx, f, " requires {:?}", join!(" ∧ ", &self.requires))?;
214        }
215        Ok(())
216    }
217}
218
219impl Pretty for Binder<FnOutput> {
220    fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
221        format_fn_root_binder(self, cx, FnRootLayerType::FnRet, "exists", f)
222    }
223}
224
225impl Pretty for FnOutput {
226    fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
227        w!(cx, f, "{:?}", &self.ret.shallow_canonicalize())?;
228        if !self.ensures.is_empty() {
229            w!(cx, f, " ensures {:?}", join!(" ∧ ", &self.ensures))?;
230        }
231        Ok(())
232    }
233}
234
235impl Pretty for Ensures {
236    fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
237        match self {
238            Ensures::Type(loc, ty) => w!(cx, f, "{:?}: {:?}", ^loc, ty),
239            Ensures::Pred(e) => w!(cx, f, "{:?}", e),
240        }
241    }
242}
243
244impl Pretty for SubsetTy {
245    fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
246        w!(cx, f, "{:?}", &self.to_ty())
247    }
248}
249
250// This is a trick to avoid pretty printing `S [S { x: 10, y: 20}]`
251// and instead just print `S[{x: 10, y: 20}]` for struct-valued indices.
252struct IdxFmt(Expr);
253
254impl PrettyNested for IdxFmt {
255    fn fmt_nested(&self, cx: &PrettyCx) -> Result<NestedString, fmt::Error> {
256        let kind = self.0.kind();
257        match kind {
258            ExprKind::Ctor(ctor, flds) => aggregate_nested(cx, ctor, flds, false),
259            ExprKind::Tuple(flds) if flds.is_empty() => {
260                Ok(NestedString { text: String::new(), key: None, children: None })
261            }
262            ExprKind::Var(Var::Free(name)) => name.fmt_nested(cx),
263            _ => self.0.fmt_nested(cx),
264        }
265    }
266}
267
268impl Pretty for IdxFmt {
269    fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
270        let e = if cx.simplify_exprs {
271            self.0.simplify(&SnapshotMap::default())
272        } else {
273            self.0.clone()
274        };
275        let mut buf = String::new();
276        match e.kind() {
277            ExprKind::Ctor(ctor, flds)
278                if let Some(adt_sort_def) = cx.adt_sort_def_of(ctor.def_id())
279                    && let Some(variant) = adt_sort_def.opt_struct_variant() =>
280            {
281                let fields = iter::zip(variant.field_names(), flds)
282                    .map(|(name, value)| FieldBind { name: *name, value: value.clone() })
283                    .collect_vec();
284                // Check if _all_ the fields are vars
285                if let Some(var_fields) = fields
286                    .iter()
287                    .map(|field| {
288                        if let ExprKind::Var(Var::Bound(debruijn, BoundReft { var, .. })) =
289                            field.value.kind()
290                        {
291                            Some((*debruijn, *var, field.value.clone()))
292                        } else {
293                            None
294                        }
295                    })
296                    .collect::<Option<Vec<_>>>()
297                {
298                    // If they are all meant to be removed, we can elide the entire index.
299                    if var_fields.iter().all(|(debruijn, var, _e)| {
300                        cx.bvar_env
301                            .should_remove_var(*debruijn, *var)
302                            .unwrap_or(false)
303                    }) {
304                        var_fields.iter().for_each(|(debruijn, var, _e)| {
305                            cx.bvar_env.mark_var_as_removed(*debruijn, *var);
306                        });
307                        // We write nothing here: we can erase the index
308                        // If we can't remove all of the vars, we can still elide the
309                        // constructor names and do our normal thing of adding @ and #
310                        //
311                        // NOTE: this is heavily copied from the var case below.
312                    } else {
313                        let mut fields = var_fields.into_iter().map(|(debruijn, var, e)| {
314                            if let Some((seen, layer_type)) =
315                                cx.bvar_env.check_if_seen_fn_root_bvar(debruijn, var)
316                                && !seen
317                            {
318                                match layer_type {
319                                    FnRootLayerType::FnArgs => {
320                                        format_cx!(cx, "@{:?}", e)
321                                    }
322                                    FnRootLayerType::FnRet => {
323                                        format_cx!(cx, "#{:?}", e)
324                                    }
325                                }
326                            } else {
327                                format_cx!(cx, "{:?}", e)
328                            }
329                        });
330                        buf.write_str(&fields.join(", "))?;
331                    }
332                } else {
333                    buf.write_str(&format_cx!(cx, "{{ {:?} }}", join!(", ", fields)))?;
334                }
335            }
336            // The first time we encounter a var in an index position where it
337            // can introduce an existential (at the function root level), we put
338            // a marker in front of it depending on where the var is.
339            //
340            // * If it's in the argument position, we use @
341            // * If it's in the return position, we use #
342            //
343            // This does not take priority over removing variables, which
344            // we check to do first.
345            //
346            // TODO: handle more complicated cases such as structs.
347            ExprKind::Var(Var::Bound(debruijn, BoundReft { var, .. })) => {
348                if cx
349                    .bvar_env
350                    .should_remove_var(*debruijn, *var)
351                    .unwrap_or(false)
352                {
353                    cx.bvar_env.mark_var_as_removed(*debruijn, *var);
354                    // don't write anything
355                } else {
356                    if let Some((seen, layer_type)) =
357                        cx.bvar_env.check_if_seen_fn_root_bvar(*debruijn, *var)
358                        && !seen
359                    {
360                        match layer_type {
361                            FnRootLayerType::FnArgs => {
362                                buf.write_str("@")?;
363                            }
364                            FnRootLayerType::FnRet => {
365                                buf.write_str("#")?;
366                            }
367                        }
368                    }
369                    buf.write_str(&format_cx!(cx, "{:?}", e))?;
370                }
371            }
372            ExprKind::Var(Var::EarlyParam(ep)) => {
373                if let Some(param) = cx.earlyparam_env.borrow_mut().as_mut()
374                    && param.insert(*ep)
375                {
376                    // FIXME: handle adding # for early params in output position
377                    buf.write_str(&format_cx!(cx, "@{:?}", e))?;
378                } else {
379                    buf.write_str(&format_cx!(cx, "{:?}", e))?;
380                }
381            }
382            _ => {
383                buf.write_str(&format_cx!(cx, "{:?}", e))?;
384            }
385        }
386        if !buf.is_empty() { write!(f, "[{}]", buf) } else { Ok(()) }
387    }
388}
389
390impl Pretty for Ty {
391    fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
392        match self.kind() {
393            TyKind::Indexed(bty, idx) => {
394                if cx.hide_refinements {
395                    w!(cx, f, "{:?}", bty)?;
396                    return Ok(());
397                }
398                if idx.is_unit() {
399                    w!(cx, f, "{:?}", bty)?;
400                } else {
401                    w!(cx, f, "{:?}{:?}", parens!(bty, !bty.is_atom()), IdxFmt(idx.clone()))?;
402                }
403                Ok(())
404            }
405            TyKind::Exists(_ty_ctor) => {
406                w!(cx, f, "{:?}", self.shallow_canonicalize())
407            }
408            TyKind::Uninit => w!(cx, f, "uninit"),
409            TyKind::StrgRef(re, loc, ty) => w!(cx, f, "&{:?} strg <{:?}: {:?}>", re, loc, ty),
410            TyKind::Ptr(pk, loc) => w!(cx, f, "ptr({:?}, {:?})", pk, loc),
411            TyKind::Discr(adt_def, place) => {
412                w!(cx, f, "discr({:?}, {:?})", adt_def.did(), ^place)
413            }
414            TyKind::Constr(pred, ty) => {
415                if cx.hide_refinements {
416                    w!(cx, f, "{:?}", ty)
417                } else {
418                    w!(cx, f, "{{ {:?} | {:?} }}", ty, pred.clone())
419                }
420            }
421            TyKind::Param(param_ty) => w!(cx, f, "{}", ^param_ty),
422            TyKind::Downcast(adt, .., variant_idx, fields) => {
423                // base-name
424                w!(cx, f, "{:?}", adt.did())?;
425                // variant-name: if it is not a struct
426                if !adt.is_struct() {
427                    w!(cx, f, "::{}", ^adt.variant(*variant_idx).name)?;
428                }
429                // fields: use curly-braces + names for structs, otherwise use parens
430                if adt.is_struct() {
431                    let field_binds = iter::zip(&adt.variant(*variant_idx).fields, fields)
432                        .map(|(field_def, value)| FieldBind { name: field_def.name, value });
433                    w!(cx, f, " {{ {:?} }}", join!(", ", field_binds))?;
434                } else if !fields.is_empty() {
435                    w!(cx, f, "({:?})", join!(", ", fields))?;
436                }
437                Ok(())
438            }
439            TyKind::Blocked(ty) => w!(cx, f, "†{:?}", ty),
440            TyKind::Infer(ty_vid) => {
441                w!(cx, f, "{ty_vid:?}")
442            }
443        }
444    }
445
446    fn default_cx(tcx: TyCtxt) -> PrettyCx {
447        PrettyCx::default(tcx).kvar_args(KVarArgs::Hide)
448    }
449}
450
451impl Pretty for PtrKind {
452    fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
453        match self {
454            PtrKind::Mut(re) => {
455                w!(cx, f, "mut")?;
456                if !cx.hide_regions {
457                    w!(cx, f, "[{:?}]", re)?;
458                }
459                Ok(())
460            }
461            PtrKind::Box => w!(cx, f, "box"),
462        }
463    }
464}
465
466impl Pretty for List<Ty> {
467    fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
468        if let [ty] = &self[..] {
469            w!(cx, f, "({:?},)", ty)
470        } else {
471            w!(cx, f, "({:?})", join!(", ", self))
472        }
473    }
474}
475
476impl Pretty for ExistentialPredicate {
477    fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
478        match self {
479            ExistentialPredicate::Trait(trait_ref) => w!(cx, f, "{:?}", trait_ref),
480            ExistentialPredicate::Projection(proj) => w!(cx, f, "({:?})", proj),
481            ExistentialPredicate::AutoTrait(def_id) => w!(cx, f, "{:?}", def_id),
482        }
483    }
484}
485
486impl Pretty for ExistentialTraitRef {
487    fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
488        w!(cx, f, "{:?}", self.def_id)?;
489        if !self.args.is_empty() {
490            w!(cx, f, "<{:?}>", join!(", ", &self.args))?;
491        }
492        Ok(())
493    }
494}
495
496impl Pretty for ExistentialProjection {
497    fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
498        w!(cx, f, "{:?}", self.def_id)?;
499        if !self.args.is_empty() {
500            w!(cx, f, "<{:?}>", join!(", ", &self.args))?;
501        }
502        w!(cx, f, " = {:?}", &self.term)
503    }
504}
505
506impl Pretty for BaseTy {
507    fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
508        match self {
509            BaseTy::Int(int_ty) => w!(cx, f, "{}", ^int_ty.name_str()),
510            BaseTy::Uint(uint_ty) => w!(cx, f, "{}", ^uint_ty.name_str()),
511            BaseTy::Bool => w!(cx, f, "bool"),
512            BaseTy::Str => w!(cx, f, "str"),
513            BaseTy::Char => w!(cx, f, "char"),
514            BaseTy::Adt(adt_def, args) => {
515                w!(cx, f, "{:?}", adt_def.did())?;
516                let args = args
517                    .iter()
518                    .filter(|arg| !cx.hide_regions || !matches!(arg, GenericArg::Lifetime(_)))
519                    .collect_vec();
520                if !args.is_empty() {
521                    w!(cx, f, "<{:?}>", join!(", ", args))?;
522                }
523                Ok(())
524            }
525            BaseTy::FnDef(def_id, args) => {
526                w!(cx, f, "FnDef({:?}[{:?}])", def_id, join!(", ", args))
527            }
528            BaseTy::Param(param) => w!(cx, f, "{}", ^param),
529            BaseTy::Float(float_ty) => w!(cx, f, "{}", ^float_ty.name_str()),
530            BaseTy::Slice(ty) => w!(cx, f, "[{:?}]", ty),
531            BaseTy::RawPtr(ty, Mutability::Mut) => w!(cx, f, "*mut {:?}", ty),
532            BaseTy::RawPtr(ty, Mutability::Not) => w!(cx, f, "*const {:?}", ty),
533            BaseTy::RawPtrMetadata(ty) => {
534                w!(cx, f, "*raw {:?}", ty)
535            }
536            BaseTy::Ref(re, ty, mutbl) => {
537                w!(cx, f, "&")?;
538                if !cx.hide_regions {
539                    w!(cx, f, "{:?} ", re)?;
540                }
541                w!(cx, f, "{}{:?}",  ^mutbl.prefix_str(), ty)
542            }
543            BaseTy::FnPtr(poly_fn_sig) => {
544                w!(cx, f, "{:?}", poly_fn_sig)
545            }
546            BaseTy::Tuple(tys) => {
547                if let [ty] = &tys[..] {
548                    w!(cx, f, "({:?},)", ty)
549                } else {
550                    w!(cx, f, "({:?})", join!(", ", tys))
551                }
552            }
553            BaseTy::Alias(kind, alias_ty) => fmt_alias_ty(cx, f, *kind, alias_ty),
554            BaseTy::Array(ty, c) => w!(cx, f, "[{:?}; {:?}]", ty, ^c),
555            BaseTy::Never => w!(cx, f, "!"),
556            BaseTy::Closure(did, args, _, _) => {
557                w!(cx, f, "{:?}<{:?}>", did, args)
558            }
559            BaseTy::Coroutine(did, resume_ty, upvars, _) => {
560                w!(cx, f, "Coroutine({:?}, {:?})", did, resume_ty)?;
561                if !upvars.is_empty() {
562                    w!(cx, f, "<{:?}>", join!(", ", upvars))?;
563                }
564                Ok(())
565            }
566            BaseTy::Dynamic(preds, re) => {
567                w!(cx, f, "dyn {:?} + {:?}", join!(" + ", preds), re)
568            }
569            BaseTy::Infer(ty_vid) => {
570                w!(cx, f, "{ty_vid:?}")
571            }
572            BaseTy::Foreign(def_id) => {
573                w!(cx, f, "{:?}", def_id)
574            }
575            BaseTy::Pat => todo!(),
576        }
577    }
578}
579
580fn fmt_alias_ty(
581    cx: &PrettyCx,
582    f: &mut fmt::Formatter<'_>,
583    kind: AliasKind,
584    alias_ty: &AliasTy,
585) -> fmt::Result {
586    match kind {
587        AliasKind::Free => {
588            w!(cx, f, "{:?}", alias_ty.def_id)?;
589            if !alias_ty.args.is_empty() {
590                w!(cx, f, "<{:?}>", join!(", ", &alias_ty.args))?;
591            }
592        }
593        AliasKind::Projection => {
594            let assoc_name = cx.tcx().item_name(alias_ty.def_id);
595            let trait_ref = cx.tcx().parent(alias_ty.def_id);
596            let trait_generic_count = cx.tcx().generics_of(trait_ref).count() - 1;
597
598            let [self_ty, args @ ..] = &alias_ty.args[..] else {
599                return w!(cx, f, "<alias_ty>");
600            };
601
602            w!(cx, f, "<{:?} as {:?}", self_ty, trait_ref)?;
603
604            let trait_generics = &args[..trait_generic_count];
605            if !trait_generics.is_empty() {
606                w!(cx, f, "<{:?}>", join!(", ", trait_generics))?;
607            }
608            w!(cx, f, ">::{}", ^assoc_name)?;
609
610            let assoc_generics = &args[trait_generic_count..];
611            if !assoc_generics.is_empty() {
612                w!(cx, f, "<{:?}>", join!(", ", assoc_generics))?;
613            }
614        }
615        AliasKind::Opaque => {
616            w!(cx, f, "{:?}", alias_ty.def_id)?;
617            if !alias_ty.args.is_empty() {
618                w!(cx, f, "<{:?}>", join!(", ", &alias_ty.args))?;
619            }
620            if !alias_ty.refine_args.is_empty() {
621                w!(cx, f, "⟨{:?}⟩", join!(", ", &alias_ty.refine_args))?;
622            }
623        }
624    }
625    Ok(())
626}
627
628impl Pretty for ValTree {
629    fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
630        match self {
631            ValTree::Leaf(v) => w!(cx, f, "Leaf({v:?})"),
632            ValTree::Branch(children) => {
633                w!(cx, f, "Branch([{:?}])", join!(", ", children))
634            }
635        }
636    }
637}
638impl Pretty for UnevaluatedConst {
639    fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
640        w!(cx, f, "UnevaluatedConst({:?}[...])", self.def)
641    }
642}
643
644impl Pretty for Const {
645    fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
646        match &self.kind {
647            ConstKind::Param(p) => w!(cx, f, "{}", ^p.name.as_str()),
648            ConstKind::Value(_, v) => w!(cx, f, "{v:?}"),
649            ConstKind::Infer(infer_const) => w!(cx, f, "{:?}", ^infer_const),
650            ConstKind::Unevaluated(uneval_const) => w!(cx, f, "{:?}", uneval_const),
651        }
652    }
653}
654
655impl Pretty for GenericArg {
656    fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
657        match self {
658            GenericArg::Ty(ty) => w!(cx, f, "{:?}", ty),
659            GenericArg::Base(ctor) => w!(cx, f, "{:?}", ctor.to_ty()),
660            GenericArg::Lifetime(re) => w!(cx, f, "{:?}", re),
661            GenericArg::Const(c) => w!(cx, f, "{:?}", c),
662        }
663    }
664}
665
666impl Pretty for VariantSig {
667    fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
668        w!(cx, f, "({:?}) => {:?}", join!(", ", self.fields()), &self.idx)
669    }
670}
671
672impl Pretty for Region {
673    fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
674        w!(cx, f, "{}", ^region_to_string(*self))
675    }
676}
677
678impl Pretty for DebruijnIndex {
679    fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
680        w!(cx, f, "^{}", ^self.as_usize())
681    }
682}
683
684impl_debug_with_default_cx!(
685    Ensures,
686    Sort,
687    Ty => "ty",
688    BaseTy,
689    FnSig,
690    GenericArg => "generic_arg",
691    VariantSig,
692    PtrKind,
693    FuncSort,
694    SortCtor,
695    SubsetTy,
696    BvSize,
697    ExistentialPredicate,
698);
699
700impl PrettyNested for SubsetTy {
701    fn fmt_nested(&self, cx: &PrettyCx) -> Result<NestedString, fmt::Error> {
702        let bty_d = self.bty.fmt_nested(cx)?;
703        let idx_d = IdxFmt(self.idx.clone()).fmt_nested(cx)?;
704        if self.pred.is_trivially_true() || matches!(self.pred.kind(), ExprKind::KVar(..)) {
705            let text = format!("{}[{}]", bty_d.text, idx_d.text);
706            let children = float_children(vec![bty_d.children, idx_d.children]);
707            Ok(NestedString { text, children, key: None })
708        } else {
709            let pred_d = self.pred.fmt_nested(cx)?;
710            let text = format!("{{ {}[{}] | {} }}", bty_d.text, idx_d.text, pred_d.text);
711            let children = float_children(vec![bty_d.children, idx_d.children, pred_d.children]);
712            Ok(NestedString { text, children, key: None })
713        }
714    }
715}
716
717impl PrettyNested for GenericArg {
718    fn fmt_nested(&self, cx: &PrettyCx) -> Result<NestedString, fmt::Error> {
719        match self {
720            GenericArg::Ty(ty) => ty.fmt_nested(cx),
721            GenericArg::Base(ctor) => {
722                // if ctor is of the form `λb. bty[b]`, just print the `bty`
723                let inner = ctor.as_ref().skip_binder();
724                if ctor.vars().len() == 1 && inner.pred.is_trivially_true() && inner.idx.is_nu() {
725                    inner.bty.fmt_nested(cx)
726                } else {
727                    cx.nested_with_bound_vars("λ", ctor.vars(), None, |prefix| {
728                        let ctor_d = ctor.skip_binder_ref().fmt_nested(cx)?;
729                        let text = format!("{}{}", prefix, ctor_d.text);
730                        Ok(NestedString { text, children: ctor_d.children, key: None })
731                    })
732                }
733            }
734            GenericArg::Lifetime(..) | GenericArg::Const(..) => debug_nested(cx, self),
735        }
736    }
737}
738
739impl PrettyNested for BaseTy {
740    fn fmt_nested(&self, cx: &PrettyCx) -> Result<NestedString, fmt::Error> {
741        match self {
742            BaseTy::Int(..)
743            | BaseTy::Uint(..)
744            | BaseTy::Bool
745            | BaseTy::Str
746            | BaseTy::Char
747            | BaseTy::Float(..)
748            | BaseTy::Param(..)
749            | BaseTy::Never
750            | BaseTy::FnPtr(..)
751            | BaseTy::FnDef(..)
752            | BaseTy::Alias(..)
753            | BaseTy::Closure(..)
754            | BaseTy::Coroutine(..)
755            | BaseTy::Dynamic(..)
756            | BaseTy::Infer(..)
757            | BaseTy::Foreign(..) => {
758                let text = format_cx!(cx, "{:?}", self);
759                Ok(NestedString { text, children: None, key: None })
760            }
761            BaseTy::Slice(ty) => {
762                let ty_d = ty.fmt_nested(cx)?;
763                let text = format!("[{}]", ty_d.text);
764                Ok(NestedString { text, children: ty_d.children, key: None })
765            }
766            BaseTy::Array(ty, c) => {
767                let ty_d = ty.fmt_nested(cx)?;
768                let text = format_cx!(cx, "[{:?}; {:?}]", ty_d.text, c);
769                Ok(NestedString { text, children: ty_d.children, key: None })
770            }
771            BaseTy::RawPtr(ty, Mutability::Mut) => {
772                let ty_d = ty.fmt_nested(cx)?;
773                let text = format!("*mut {}", ty_d.text);
774                Ok(NestedString { text, children: ty_d.children, key: None })
775            }
776            BaseTy::RawPtr(ty, Mutability::Not) => {
777                let ty_d = ty.fmt_nested(cx)?;
778                let text = format!("*const {}", ty_d.text);
779                Ok(NestedString { text, children: ty_d.children, key: None })
780            }
781            BaseTy::RawPtrMetadata(ty) => {
782                let ty_d = ty.fmt_nested(cx)?;
783                let text = format!("*raw {}", ty_d.text);
784                Ok(NestedString { text, children: ty_d.children, key: None })
785            }
786            BaseTy::Ref(_, ty, mutbl) => {
787                let ty_d = ty.fmt_nested(cx)?;
788                let prefix = mutbl.prefix_str();
789                let text = if prefix.is_empty() {
790                    format!("&{}", ty_d.text)
791                } else {
792                    format!("&{} {}", prefix, ty_d.text)
793                };
794                Ok(NestedString { text, children: ty_d.children, key: None })
795            }
796            BaseTy::Tuple(tys) => {
797                let mut texts = vec![];
798                let mut kidss = vec![];
799                for ty in tys {
800                    let ty_d = ty.fmt_nested(cx)?;
801                    texts.push(ty_d.text);
802                    kidss.push(ty_d.children);
803                }
804                let text = if let [text] = &texts[..] {
805                    format!("({text},)")
806                } else {
807                    format!("({})", texts.join(", "))
808                };
809                let children = float_children(kidss);
810                Ok(NestedString { text, children, key: None })
811            }
812            BaseTy::Adt(adt_def, args) => {
813                let mut texts = vec![];
814                let mut kidss = vec![];
815                for arg in args {
816                    let arg_d = arg.fmt_nested(cx)?;
817                    texts.push(arg_d.text);
818                    kidss.push(arg_d.children);
819                }
820                let args_str = if !args.is_empty() {
821                    format!("<{}>", texts.join(", "))
822                } else {
823                    String::new()
824                };
825                let text = format_cx!(cx, "{:?}{:?}", adt_def.did(), args_str);
826                let children = float_children(kidss);
827                Ok(NestedString { text, children, key: None })
828            }
829            BaseTy::Pat => todo!(),
830        }
831    }
832}
833
834impl PrettyNested for Ty {
835    fn fmt_nested(&self, cx: &PrettyCx) -> Result<NestedString, fmt::Error> {
836        match self.kind() {
837            TyKind::Indexed(bty, idx) => {
838                let bty_d = bty.fmt_nested(cx)?;
839                let idx_d = IdxFmt(idx.clone()).fmt_nested(cx)?;
840                let text = if idx_d.text.is_empty() {
841                    bty_d.text
842                } else {
843                    format!("{}[{}]", bty_d.text, idx_d.text)
844                };
845                let children = float_children(vec![bty_d.children, idx_d.children]);
846                Ok(NestedString { text, children, key: None })
847            }
848            TyKind::Exists(ty_ctor) => {
849                // TODO: remove redundant vars; see Ty
850                // if ctor is of the form `∃b. bty[b]`, just print the `bty`
851                if ty_ctor.vars().len() == 1
852                    && let TyKind::Indexed(bty, idx) = ty_ctor.skip_binder_ref().kind()
853                    && idx.is_nu()
854                {
855                    bty.fmt_nested(cx)
856                } else {
857                    cx.nested_with_bound_vars("∃", ty_ctor.vars(), None, |exi_str| {
858                        let ty_ctor_d = ty_ctor.skip_binder_ref().fmt_nested(cx)?;
859                        let text = format!("{}{}", exi_str, ty_ctor_d.text);
860                        Ok(NestedString { text, children: ty_ctor_d.children, key: None })
861                    })
862                }
863            }
864            TyKind::Constr(expr, ty) => {
865                let expr_d = expr.fmt_nested(cx)?;
866                let ty_d = ty.fmt_nested(cx)?;
867                let text = format!("{{ {} | {} }}", ty_d.text, expr_d.text);
868                let children = float_children(vec![expr_d.children, ty_d.children]);
869                Ok(NestedString { text, children, key: None })
870            }
871            TyKind::StrgRef(re, loc, ty) => {
872                let ty_d = ty.fmt_nested(cx)?;
873                let text = format!("&{:?} strg <{:?}: {}>", re, loc, ty_d.text);
874                Ok(NestedString { text, children: ty_d.children, key: None })
875            }
876            TyKind::Blocked(ty) => {
877                let ty_d = ty.fmt_nested(cx)?;
878                let text = format!("†{}", ty_d.text);
879                Ok(NestedString { text, children: ty_d.children, key: None })
880            }
881            TyKind::Downcast(adt, .., variant_idx, fields) => {
882                let is_struct = adt.is_struct();
883                let mut text = format_cx!(cx, "{:?}", adt.did());
884                if !is_struct {
885                    text.push_str(&format!("::{}", adt.variant(*variant_idx).name));
886                }
887                if is_struct {
888                    text.push_str("{..}");
889                } else {
890                    text.push_str("(..)");
891                }
892                let keys: Vec<String> = if is_struct {
893                    adt.variant(*variant_idx)
894                        .fields
895                        .iter()
896                        .map(|f| f.name.to_string())
897                        .collect()
898                } else {
899                    (0..fields.len()).map(|i| format!("{i}")).collect()
900                };
901                let mut children = vec![];
902                for (key, field) in keys.into_iter().zip(fields) {
903                    let field_d = field.fmt_nested(cx)?;
904                    children.push(NestedString { key: Some(key), ..field_d });
905                }
906                Ok(NestedString { text, children: Some(children), key: None })
907            }
908            TyKind::Param(..)
909            | TyKind::Uninit
910            | TyKind::Ptr(..)
911            | TyKind::Discr(..)
912            | TyKind::Infer(..) => {
913                let text = format!("{self:?}");
914                Ok(NestedString { text, children: None, key: None })
915            }
916        }
917    }
918}