Skip to main content

flux_middle/rty/
pretty.rs

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