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((def_id, _)) = ctor.def_id_and_variant()
279                    && let Some(adt_sort_def) = cx.adt_sort_def_of(def_id)
280                    && let Some(variant) = adt_sort_def.opt_struct_variant() =>
281            {
282                let fields = iter::zip(variant.field_names(), flds)
283                    .map(|(name, value)| FieldBind { name: *name, value: value.clone() })
284                    .collect_vec();
285                // Check if _all_ the fields are vars
286                if let Some(var_fields) = fields
287                    .iter()
288                    .map(|field| {
289                        if let ExprKind::Var(Var::Bound(debruijn, BoundReft { var, .. })) =
290                            field.value.kind()
291                        {
292                            Some((*debruijn, *var, field.value.clone()))
293                        } else {
294                            None
295                        }
296                    })
297                    .collect::<Option<Vec<_>>>()
298                {
299                    // If they are all meant to be removed, we can elide the entire index.
300                    if var_fields.iter().all(|(debruijn, var, _e)| {
301                        cx.bvar_env
302                            .should_remove_var(*debruijn, *var)
303                            .unwrap_or(false)
304                    }) {
305                        var_fields.iter().for_each(|(debruijn, var, _e)| {
306                            cx.bvar_env.mark_var_as_removed(*debruijn, *var);
307                        });
308                        // We write nothing here: we can erase the index
309                        // If we can't remove all of the vars, we can still elide the
310                        // constructor names and do our normal thing of adding @ and #
311                        //
312                        // NOTE: this is heavily copied from the var case below.
313                    } else {
314                        let mut fields = var_fields.into_iter().map(|(debruijn, var, e)| {
315                            if let Some((seen, layer_type)) =
316                                cx.bvar_env.check_if_seen_fn_root_bvar(debruijn, var)
317                                && !seen
318                            {
319                                match layer_type {
320                                    FnRootLayerType::FnArgs => {
321                                        format_cx!(cx, "@{:?}", e)
322                                    }
323                                    FnRootLayerType::FnRet => {
324                                        format_cx!(cx, "#{:?}", e)
325                                    }
326                                }
327                            } else {
328                                format_cx!(cx, "{:?}", e)
329                            }
330                        });
331                        buf.write_str(&fields.join(", "))?;
332                    }
333                } else {
334                    buf.write_str(&format_cx!(cx, "{{ {:?} }}", join!(", ", fields)))?;
335                }
336            }
337            // The first time we encounter a var in an index position where it
338            // can introduce an existential (at the function root level), we put
339            // a marker in front of it depending on where the var is.
340            //
341            // * If it's in the argument position, we use @
342            // * If it's in the return position, we use #
343            //
344            // This does not take priority over removing variables, which
345            // we check to do first.
346            //
347            // TODO: handle more complicated cases such as structs.
348            ExprKind::Var(Var::Bound(debruijn, BoundReft { var, .. })) => {
349                if cx
350                    .bvar_env
351                    .should_remove_var(*debruijn, *var)
352                    .unwrap_or(false)
353                {
354                    cx.bvar_env.mark_var_as_removed(*debruijn, *var);
355                    // don't write anything
356                } else {
357                    if let Some((seen, layer_type)) =
358                        cx.bvar_env.check_if_seen_fn_root_bvar(*debruijn, *var)
359                        && !seen
360                    {
361                        match layer_type {
362                            FnRootLayerType::FnArgs => {
363                                buf.write_str("@")?;
364                            }
365                            FnRootLayerType::FnRet => {
366                                buf.write_str("#")?;
367                            }
368                        }
369                    }
370                    buf.write_str(&format_cx!(cx, "{:?}", e))?;
371                }
372            }
373            ExprKind::Var(Var::EarlyParam(ep)) => {
374                if let Some(param) = cx.earlyparam_env.borrow_mut().as_mut()
375                    && param.insert(*ep)
376                {
377                    // FIXME: handle adding # for early params in output position
378                    buf.write_str(&format_cx!(cx, "@{:?}", e))?;
379                } else {
380                    buf.write_str(&format_cx!(cx, "{:?}", e))?;
381                }
382            }
383            _ => {
384                buf.write_str(&format_cx!(cx, "{:?}", e))?;
385            }
386        }
387        if !buf.is_empty() { write!(f, "[{}]", buf) } else { Ok(()) }
388    }
389}
390
391impl Pretty for Ty {
392    fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
393        match self.kind() {
394            TyKind::Indexed(bty, idx) => {
395                if cx.hide_refinements {
396                    w!(cx, f, "{:?}", bty)?;
397                    return Ok(());
398                }
399                if idx.is_unit() {
400                    w!(cx, f, "{:?}", bty)?;
401                } else {
402                    w!(cx, f, "{:?}{:?}", parens!(bty, !bty.is_atom()), IdxFmt(idx.clone()))?;
403                }
404                Ok(())
405            }
406            TyKind::Exists(_ty_ctor) => {
407                w!(cx, f, "{:?}", self.shallow_canonicalize())
408            }
409            TyKind::Uninit => w!(cx, f, "uninit"),
410            TyKind::StrgRef(re, loc, ty) => w!(cx, f, "&{:?} strg <{:?}: {:?}>", re, loc, ty),
411            TyKind::Ptr(pk, loc) => w!(cx, f, "ptr({:?}, {:?})", pk, loc),
412            TyKind::Discr(adt_def, place) => {
413                w!(cx, f, "discr({:?}, {:?})", adt_def.did(), ^place)
414            }
415            TyKind::Constr(pred, ty) => {
416                if cx.hide_refinements {
417                    w!(cx, f, "{:?}", ty)
418                } else {
419                    w!(cx, f, "{{ {:?} | {:?} }}", ty, pred.clone())
420                }
421            }
422            TyKind::Param(param_ty) => w!(cx, f, "{}", ^param_ty),
423            TyKind::Downcast(adt, .., variant_idx, fields) => {
424                // base-name
425                w!(cx, f, "{:?}", adt.did())?;
426                // variant-name: if it is not a struct
427                if !adt.is_struct() {
428                    w!(cx, f, "::{}", ^adt.variant(*variant_idx).name)?;
429                }
430                // fields: use curly-braces + names for structs, otherwise use parens
431                if adt.is_struct() {
432                    let field_binds = iter::zip(&adt.variant(*variant_idx).fields, fields)
433                        .map(|(field_def, value)| FieldBind { name: field_def.name, value });
434                    w!(cx, f, " {{ {:?} }}", join!(", ", field_binds))?;
435                } else if !fields.is_empty() {
436                    w!(cx, f, "({:?})", join!(", ", fields))?;
437                }
438                Ok(())
439            }
440            TyKind::Blocked(ty) => w!(cx, f, "†{:?}", ty),
441            TyKind::Infer(ty_vid) => {
442                w!(cx, f, "{ty_vid:?}")
443            }
444        }
445    }
446
447    fn default_cx(tcx: TyCtxt) -> PrettyCx {
448        PrettyCx::default(tcx).kvar_args(KVarArgs::Hide)
449    }
450}
451
452impl Pretty for PtrKind {
453    fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
454        match self {
455            PtrKind::Mut(re) => {
456                w!(cx, f, "mut")?;
457                if !cx.hide_regions {
458                    w!(cx, f, "[{:?}]", re)?;
459                }
460                Ok(())
461            }
462            PtrKind::Box => w!(cx, f, "box"),
463        }
464    }
465}
466
467impl Pretty for List<Ty> {
468    fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
469        if let [ty] = &self[..] {
470            w!(cx, f, "({:?},)", ty)
471        } else {
472            w!(cx, f, "({:?})", join!(", ", self))
473        }
474    }
475}
476
477impl Pretty for ExistentialPredicate {
478    fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
479        match self {
480            ExistentialPredicate::Trait(trait_ref) => w!(cx, f, "{:?}", trait_ref),
481            ExistentialPredicate::Projection(proj) => w!(cx, f, "({:?})", proj),
482            ExistentialPredicate::AutoTrait(def_id) => w!(cx, f, "{:?}", def_id),
483        }
484    }
485}
486
487impl Pretty for ExistentialTraitRef {
488    fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
489        w!(cx, f, "{:?}", self.def_id)?;
490        if !self.args.is_empty() {
491            w!(cx, f, "<{:?}>", join!(", ", &self.args))?;
492        }
493        Ok(())
494    }
495}
496
497impl Pretty for ExistentialProjection {
498    fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
499        w!(cx, f, "{:?}", self.def_id)?;
500        if !self.args.is_empty() {
501            w!(cx, f, "<{:?}>", join!(", ", &self.args))?;
502        }
503        w!(cx, f, " = {:?}", &self.term)
504    }
505}
506
507impl Pretty for BaseTy {
508    fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
509        match self {
510            BaseTy::Int(int_ty) => w!(cx, f, "{}", ^int_ty.name_str()),
511            BaseTy::Uint(uint_ty) => w!(cx, f, "{}", ^uint_ty.name_str()),
512            BaseTy::Bool => w!(cx, f, "bool"),
513            BaseTy::Str => w!(cx, f, "str"),
514            BaseTy::Char => w!(cx, f, "char"),
515            BaseTy::Adt(adt_def, args) => {
516                w!(cx, f, "{:?}", adt_def.did())?;
517                let args = args
518                    .iter()
519                    .filter(|arg| !cx.hide_regions || !matches!(arg, GenericArg::Lifetime(_)))
520                    .collect_vec();
521                if !args.is_empty() {
522                    w!(cx, f, "<{:?}>", join!(", ", args))?;
523                }
524                Ok(())
525            }
526            BaseTy::FnDef(def_id, args) => {
527                w!(cx, f, "FnDef({:?}[{:?}])", def_id, join!(", ", args))
528            }
529            BaseTy::Param(param) => w!(cx, f, "{}", ^param),
530            BaseTy::Float(float_ty) => w!(cx, f, "{}", ^float_ty.name_str()),
531            BaseTy::Slice(ty) => w!(cx, f, "[{:?}]", ty),
532            BaseTy::RawPtr(ty, Mutability::Mut) => w!(cx, f, "*mut {:?}", ty),
533            BaseTy::RawPtr(ty, Mutability::Not) => w!(cx, f, "*const {:?}", ty),
534            BaseTy::RawPtrMetadata(ty) => {
535                w!(cx, f, "*raw {:?}", ty)
536            }
537            BaseTy::Ref(re, ty, mutbl) => {
538                w!(cx, f, "&")?;
539                if !cx.hide_regions {
540                    w!(cx, f, "{:?} ", re)?;
541                }
542                w!(cx, f, "{}{:?}",  ^mutbl.prefix_str(), ty)
543            }
544            BaseTy::FnPtr(poly_fn_sig) => {
545                w!(cx, f, "{:?}", poly_fn_sig)
546            }
547            BaseTy::Tuple(tys) => {
548                if let [ty] = &tys[..] {
549                    w!(cx, f, "({:?},)", ty)
550                } else {
551                    w!(cx, f, "({:?})", join!(", ", tys))
552                }
553            }
554            BaseTy::Alias(kind, alias_ty) => fmt_alias_ty(cx, f, *kind, alias_ty),
555            BaseTy::Array(ty, c) => w!(cx, f, "[{:?}; {:?}]", ty, ^c),
556            BaseTy::Never => w!(cx, f, "!"),
557            BaseTy::Closure(did, args, _, _) => {
558                w!(cx, f, "{:?}<{:?}>", did, args)
559            }
560            BaseTy::Coroutine(did, resume_ty, upvars, _) => {
561                w!(cx, f, "Coroutine({:?}, {:?})", did, resume_ty)?;
562                if !upvars.is_empty() {
563                    w!(cx, f, "<{:?}>", join!(", ", upvars))?;
564                }
565                Ok(())
566            }
567            BaseTy::Dynamic(preds, re) => {
568                w!(cx, f, "dyn {:?} + {:?}", join!(" + ", preds), re)
569            }
570            BaseTy::Infer(ty_vid) => {
571                w!(cx, f, "{ty_vid:?}")
572            }
573            BaseTy::Foreign(def_id) => {
574                w!(cx, f, "{:?}", def_id)
575            }
576            BaseTy::Pat => todo!(),
577        }
578    }
579}
580
581fn fmt_alias_ty(
582    cx: &PrettyCx,
583    f: &mut fmt::Formatter<'_>,
584    kind: AliasKind,
585    alias_ty: &AliasTy,
586) -> fmt::Result {
587    match kind {
588        AliasKind::Free => {
589            w!(cx, f, "{:?}", alias_ty.def_id)?;
590            if !alias_ty.args.is_empty() {
591                w!(cx, f, "<{:?}>", join!(", ", &alias_ty.args))?;
592            }
593        }
594        AliasKind::Projection => {
595            let assoc_name = cx.tcx().item_name(alias_ty.def_id);
596            let trait_ref = cx.tcx().parent(alias_ty.def_id);
597            let trait_generic_count = cx.tcx().generics_of(trait_ref).count() - 1;
598
599            let [self_ty, args @ ..] = &alias_ty.args[..] else {
600                return w!(cx, f, "<alias_ty>");
601            };
602
603            w!(cx, f, "<{:?} as {:?}", self_ty, trait_ref)?;
604
605            let trait_generics = &args[..trait_generic_count];
606            if !trait_generics.is_empty() {
607                w!(cx, f, "<{:?}>", join!(", ", trait_generics))?;
608            }
609            w!(cx, f, ">::{}", ^assoc_name)?;
610
611            let assoc_generics = &args[trait_generic_count..];
612            if !assoc_generics.is_empty() {
613                w!(cx, f, "<{:?}>", join!(", ", assoc_generics))?;
614            }
615        }
616        AliasKind::Opaque => {
617            w!(cx, f, "{:?}", alias_ty.def_id)?;
618            if !alias_ty.args.is_empty() {
619                w!(cx, f, "<{:?}>", join!(", ", &alias_ty.args))?;
620            }
621            if !alias_ty.refine_args.is_empty() {
622                w!(cx, f, "⟨{:?}⟩", join!(", ", &alias_ty.refine_args))?;
623            }
624        }
625    }
626    Ok(())
627}
628
629impl Pretty for ValTree {
630    fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
631        match self {
632            ValTree::Leaf(v) => w!(cx, f, "Leaf({v:?})"),
633            ValTree::Branch(children) => {
634                w!(cx, f, "Branch([{:?}])", join!(", ", children))
635            }
636        }
637    }
638}
639impl Pretty for UnevaluatedConst {
640    fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
641        w!(cx, f, "UnevaluatedConst({:?}[...])", self.def)
642    }
643}
644
645impl Pretty for Const {
646    fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
647        match &self.kind {
648            ConstKind::Param(p) => w!(cx, f, "{}", ^p.name.as_str()),
649            ConstKind::Value(_, v) => w!(cx, f, "{v:?}"),
650            ConstKind::Infer(infer_const) => w!(cx, f, "{:?}", ^infer_const),
651            ConstKind::Unevaluated(uneval_const) => w!(cx, f, "{:?}", uneval_const),
652        }
653    }
654}
655
656impl Pretty for GenericArg {
657    fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
658        match self {
659            GenericArg::Ty(ty) => w!(cx, f, "{:?}", ty),
660            GenericArg::Base(ctor) => w!(cx, f, "{:?}", ctor.to_ty()),
661            GenericArg::Lifetime(re) => w!(cx, f, "{:?}", re),
662            GenericArg::Const(c) => w!(cx, f, "{:?}", c),
663        }
664    }
665}
666
667impl Pretty for VariantSig {
668    fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
669        w!(cx, f, "({:?}) => {:?}", join!(", ", self.fields()), &self.idx)
670    }
671}
672
673impl Pretty for Region {
674    fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
675        w!(cx, f, "{}", ^region_to_string(*self))
676    }
677}
678
679impl Pretty for DebruijnIndex {
680    fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
681        w!(cx, f, "^{}", ^self.as_usize())
682    }
683}
684
685impl_debug_with_default_cx!(
686    Ensures,
687    Sort,
688    Ty => "ty",
689    BaseTy,
690    FnSig,
691    GenericArg => "generic_arg",
692    VariantSig,
693    PtrKind,
694    FuncSort,
695    SortCtor,
696    SubsetTy,
697    BvSize,
698    ExistentialPredicate,
699);
700
701impl PrettyNested for SubsetTy {
702    fn fmt_nested(&self, cx: &PrettyCx) -> Result<NestedString, fmt::Error> {
703        let bty_d = self.bty.fmt_nested(cx)?;
704        let idx_d = IdxFmt(self.idx.clone()).fmt_nested(cx)?;
705        if self.pred.is_trivially_true() || matches!(self.pred.kind(), ExprKind::KVar(..)) {
706            let text = format!("{}[{}]", bty_d.text, idx_d.text);
707            let children = float_children(vec![bty_d.children, idx_d.children]);
708            Ok(NestedString { text, children, key: None })
709        } else {
710            let pred_d = self.pred.fmt_nested(cx)?;
711            let text = format!("{{ {}[{}] | {} }}", bty_d.text, idx_d.text, pred_d.text);
712            let children = float_children(vec![bty_d.children, idx_d.children, pred_d.children]);
713            Ok(NestedString { text, children, key: None })
714        }
715    }
716}
717
718impl PrettyNested for GenericArg {
719    fn fmt_nested(&self, cx: &PrettyCx) -> Result<NestedString, fmt::Error> {
720        match self {
721            GenericArg::Ty(ty) => ty.fmt_nested(cx),
722            GenericArg::Base(ctor) => {
723                // if ctor is of the form `λb. bty[b]`, just print the `bty`
724                let inner = ctor.as_ref().skip_binder();
725                if ctor.vars().len() == 1 && inner.pred.is_trivially_true() && inner.idx.is_nu() {
726                    inner.bty.fmt_nested(cx)
727                } else {
728                    cx.nested_with_bound_vars("λ", ctor.vars(), None, |prefix| {
729                        let ctor_d = ctor.skip_binder_ref().fmt_nested(cx)?;
730                        let text = format!("{}{}", prefix, ctor_d.text);
731                        Ok(NestedString { text, children: ctor_d.children, key: None })
732                    })
733                }
734            }
735            GenericArg::Lifetime(..) | GenericArg::Const(..) => debug_nested(cx, self),
736        }
737    }
738}
739
740impl PrettyNested for BaseTy {
741    fn fmt_nested(&self, cx: &PrettyCx) -> Result<NestedString, fmt::Error> {
742        match self {
743            BaseTy::Int(..)
744            | BaseTy::Uint(..)
745            | BaseTy::Bool
746            | BaseTy::Str
747            | BaseTy::Char
748            | BaseTy::Float(..)
749            | BaseTy::Param(..)
750            | BaseTy::Never
751            | BaseTy::FnPtr(..)
752            | BaseTy::FnDef(..)
753            | BaseTy::Alias(..)
754            | BaseTy::Closure(..)
755            | BaseTy::Coroutine(..)
756            | BaseTy::Dynamic(..)
757            | BaseTy::Infer(..)
758            | BaseTy::Foreign(..) => {
759                let text = format_cx!(cx, "{:?}", self);
760                Ok(NestedString { text, children: None, key: None })
761            }
762            BaseTy::Slice(ty) => {
763                let ty_d = ty.fmt_nested(cx)?;
764                let text = format!("[{}]", ty_d.text);
765                Ok(NestedString { text, children: ty_d.children, key: None })
766            }
767            BaseTy::Array(ty, c) => {
768                let ty_d = ty.fmt_nested(cx)?;
769                let text = format_cx!(cx, "[{:?}; {:?}]", ty_d.text, c);
770                Ok(NestedString { text, children: ty_d.children, key: None })
771            }
772            BaseTy::RawPtr(ty, Mutability::Mut) => {
773                let ty_d = ty.fmt_nested(cx)?;
774                let text = format!("*mut {}", ty_d.text);
775                Ok(NestedString { text, children: ty_d.children, key: None })
776            }
777            BaseTy::RawPtr(ty, Mutability::Not) => {
778                let ty_d = ty.fmt_nested(cx)?;
779                let text = format!("*const {}", ty_d.text);
780                Ok(NestedString { text, children: ty_d.children, key: None })
781            }
782            BaseTy::RawPtrMetadata(ty) => {
783                let ty_d = ty.fmt_nested(cx)?;
784                let text = format!("*raw {}", ty_d.text);
785                Ok(NestedString { text, children: ty_d.children, key: None })
786            }
787            BaseTy::Ref(_, ty, mutbl) => {
788                let ty_d = ty.fmt_nested(cx)?;
789                let prefix = mutbl.prefix_str();
790                let text = if prefix.is_empty() {
791                    format!("&{}", ty_d.text)
792                } else {
793                    format!("&{} {}", prefix, ty_d.text)
794                };
795                Ok(NestedString { text, children: ty_d.children, key: None })
796            }
797            BaseTy::Tuple(tys) => {
798                let mut texts = vec![];
799                let mut kidss = vec![];
800                for ty in tys {
801                    let ty_d = ty.fmt_nested(cx)?;
802                    texts.push(ty_d.text);
803                    kidss.push(ty_d.children);
804                }
805                let text = if let [text] = &texts[..] {
806                    format!("({text},)")
807                } else {
808                    format!("({})", texts.join(", "))
809                };
810                let children = float_children(kidss);
811                Ok(NestedString { text, children, key: None })
812            }
813            BaseTy::Adt(adt_def, args) => {
814                let mut texts = vec![];
815                let mut kidss = vec![];
816                for arg in args {
817                    let arg_d = arg.fmt_nested(cx)?;
818                    texts.push(arg_d.text);
819                    kidss.push(arg_d.children);
820                }
821                let args_str = if !args.is_empty() {
822                    format!("<{}>", texts.join(", "))
823                } else {
824                    String::new()
825                };
826                let text = format_cx!(cx, "{:?}{:?}", adt_def.did(), args_str);
827                let children = float_children(kidss);
828                Ok(NestedString { text, children, key: None })
829            }
830            BaseTy::Pat => todo!(),
831        }
832    }
833}
834
835impl PrettyNested for Ty {
836    fn fmt_nested(&self, cx: &PrettyCx) -> Result<NestedString, fmt::Error> {
837        match self.kind() {
838            TyKind::Indexed(bty, idx) => {
839                let bty_d = bty.fmt_nested(cx)?;
840                let idx_d = IdxFmt(idx.clone()).fmt_nested(cx)?;
841                let text = if idx_d.text.is_empty() {
842                    bty_d.text
843                } else {
844                    format!("{}[{}]", bty_d.text, idx_d.text)
845                };
846                let children = float_children(vec![bty_d.children, idx_d.children]);
847                Ok(NestedString { text, children, key: None })
848            }
849            TyKind::Exists(ty_ctor) => {
850                // TODO: remove redundant vars; see Ty
851                // if ctor is of the form `∃b. bty[b]`, just print the `bty`
852                if ty_ctor.vars().len() == 1
853                    && let TyKind::Indexed(bty, idx) = ty_ctor.skip_binder_ref().kind()
854                    && idx.is_nu()
855                {
856                    bty.fmt_nested(cx)
857                } else {
858                    cx.nested_with_bound_vars("∃", ty_ctor.vars(), None, |exi_str| {
859                        let ty_ctor_d = ty_ctor.skip_binder_ref().fmt_nested(cx)?;
860                        let text = format!("{}{}", exi_str, ty_ctor_d.text);
861                        Ok(NestedString { text, children: ty_ctor_d.children, key: None })
862                    })
863                }
864            }
865            TyKind::Constr(expr, ty) => {
866                let expr_d = expr.fmt_nested(cx)?;
867                let ty_d = ty.fmt_nested(cx)?;
868                let text = format!("{{ {} | {} }}", ty_d.text, expr_d.text);
869                let children = float_children(vec![expr_d.children, ty_d.children]);
870                Ok(NestedString { text, children, key: None })
871            }
872            TyKind::StrgRef(re, loc, ty) => {
873                let ty_d = ty.fmt_nested(cx)?;
874                let text = format!("&{:?} strg <{:?}: {}>", re, loc, ty_d.text);
875                Ok(NestedString { text, children: ty_d.children, key: None })
876            }
877            TyKind::Blocked(ty) => {
878                let ty_d = ty.fmt_nested(cx)?;
879                let text = format!("†{}", ty_d.text);
880                Ok(NestedString { text, children: ty_d.children, key: None })
881            }
882            TyKind::Downcast(adt, .., variant_idx, fields) => {
883                let is_struct = adt.is_struct();
884                let mut text = format_cx!(cx, "{:?}", adt.did());
885                if !is_struct {
886                    text.push_str(&format!("::{}", adt.variant(*variant_idx).name));
887                }
888                if is_struct {
889                    text.push_str("{..}");
890                } else {
891                    text.push_str("(..)");
892                }
893                let keys: Vec<String> = if is_struct {
894                    adt.variant(*variant_idx)
895                        .fields
896                        .iter()
897                        .map(|f| f.name.to_string())
898                        .collect()
899                } else {
900                    (0..fields.len()).map(|i| format!("{i}")).collect()
901                };
902                let mut children = vec![];
903                for (key, field) in keys.into_iter().zip(fields) {
904                    let field_d = field.fmt_nested(cx)?;
905                    children.push(NestedString { key: Some(key), ..field_d });
906                }
907                Ok(NestedString { text, children: Some(children), key: None })
908            }
909            TyKind::Param(..)
910            | TyKind::Uninit
911            | TyKind::Ptr(..)
912            | TyKind::Discr(..)
913            | TyKind::Infer(..) => {
914                let text = format!("{self:?}");
915                Ok(NestedString { text, children: None, key: None })
916            }
917        }
918    }
919}