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::{UnevaluatedConst, 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(kind, alias_ty) => {
150                fmt_alias_ty(cx, f, *kind, 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.type_of(param.def_id).instantiate(tcx, earlier_args);
631                        if arg.to_rustc(tcx) != rustc_middle::ty::GenericArg::from(default_ty) {
632                            break;
633                        }
634                        args.pop();
635                    }
636                }
637                if !args.is_empty() {
638                    w!(cx, f, "<{:?}>", join!(", ", args))?;
639                }
640                Ok(())
641            }
642            BaseTy::FnDef(def_id, args) => {
643                w!(cx, f, "FnDef({:?}[{:?}])", def_id, join!(", ", args))
644            }
645            BaseTy::Param(param) => w!(cx, f, "{}", ^param),
646            BaseTy::Float(float_ty) => w!(cx, f, "{}", ^float_ty.name_str()),
647            BaseTy::Slice(ty) => w!(cx, f, "[{:?}]", ty),
648            BaseTy::RawPtr(ty, Mutability::Mut) => w!(cx, f, "*mut {:?}", ty),
649            BaseTy::RawPtr(ty, Mutability::Not) => w!(cx, f, "*const {:?}", ty),
650            BaseTy::RawPtrMetadata(ty) => {
651                w!(cx, f, "*raw {:?}", ty)
652            }
653            BaseTy::Ref(re, ty, mutbl) => {
654                w!(cx, f, "&")?;
655                if !cx.hide_regions {
656                    w!(cx, f, "{:?} ", re)?;
657                }
658                w!(cx, f, "{}{:?}",  ^mutbl.prefix_str(), ty)
659            }
660            BaseTy::FnPtr(poly_fn_sig) => {
661                w!(cx, f, "{:?}", poly_fn_sig)
662            }
663            BaseTy::Tuple(tys) => {
664                if let [ty] = &tys[..] {
665                    w!(cx, f, "({:?},)", ty)
666                } else {
667                    w!(cx, f, "({:?})", join!(", ", tys))
668                }
669            }
670            BaseTy::Alias(kind, alias_ty) => fmt_alias_ty(cx, f, *kind, alias_ty),
671            BaseTy::Array(ty, c) => w!(cx, f, "[{:?}; {:?}]", ty, ^c),
672            BaseTy::Never => w!(cx, f, "!"),
673            BaseTy::Closure(did, args, _, _) => {
674                w!(cx, f, "{:?}<{:?}>", did, args)
675            }
676            BaseTy::Coroutine(did, resume_ty, upvars, _) => {
677                w!(cx, f, "Coroutine({:?}, {:?})", did, resume_ty)?;
678                if !upvars.is_empty() {
679                    w!(cx, f, "<{:?}>", join!(", ", upvars))?;
680                }
681                Ok(())
682            }
683            BaseTy::Dynamic(preds, re) => {
684                w!(cx, f, "dyn {:?} + {:?}", join!(" + ", preds), re)
685            }
686            BaseTy::Infer(ty_vid) => {
687                w!(cx, f, "{ty_vid:?}")
688            }
689            BaseTy::Foreign(def_id) => {
690                w!(cx, f, "{:?}", def_id)
691            }
692            BaseTy::Pat => todo!(),
693        }
694    }
695}
696
697fn fmt_alias_ty(
698    cx: &PrettyCx,
699    f: &mut fmt::Formatter<'_>,
700    kind: AliasKind,
701    alias_ty: &AliasTy,
702) -> fmt::Result {
703    match kind {
704        AliasKind::Free => {
705            w!(cx, f, "{:?}", alias_ty.def_id)?;
706            if !alias_ty.args.is_empty() {
707                w!(cx, f, "<{:?}>", join!(", ", &alias_ty.args))?;
708            }
709        }
710        AliasKind::Projection => {
711            let assoc_name = cx.tcx().item_name(alias_ty.def_id);
712            let trait_ref = cx.tcx().parent(alias_ty.def_id);
713            let trait_generic_count = cx.tcx().generics_of(trait_ref).count() - 1;
714
715            let [self_ty, args @ ..] = &alias_ty.args[..] else {
716                return w!(cx, f, "<alias_ty>");
717            };
718
719            w!(cx, f, "<{:?} as {:?}", self_ty, trait_ref)?;
720
721            let trait_generics = &args[..trait_generic_count];
722            if !trait_generics.is_empty() {
723                w!(cx, f, "<{:?}>", join!(", ", trait_generics))?;
724            }
725            w!(cx, f, ">::{}", ^assoc_name)?;
726
727            let assoc_generics = &args[trait_generic_count..];
728            if !assoc_generics.is_empty() {
729                w!(cx, f, "<{:?}>", join!(", ", assoc_generics))?;
730            }
731        }
732        AliasKind::Opaque => {
733            w!(cx, f, "{:?}", alias_ty.def_id)?;
734            if !alias_ty.args.is_empty() {
735                w!(cx, f, "<{:?}>", join!(", ", &alias_ty.args))?;
736            }
737            if !alias_ty.refine_args.is_empty() {
738                w!(cx, f, "⟨{:?}⟩", join!(", ", &alias_ty.refine_args))?;
739            }
740        }
741    }
742    Ok(())
743}
744
745impl Pretty for ValTree {
746    fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
747        match self {
748            ValTree::Leaf(v) => w!(cx, f, "Leaf({v:?})"),
749            ValTree::Branch(children) => {
750                w!(cx, f, "Branch([{:?}])", join!(", ", children))
751            }
752        }
753    }
754}
755impl Pretty for UnevaluatedConst {
756    fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
757        w!(cx, f, "UnevaluatedConst({:?}[...])", self.def)
758    }
759}
760
761impl Pretty for Const {
762    fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
763        match &self.kind {
764            ConstKind::Param(p) => w!(cx, f, "{}", ^p.name.as_str()),
765            ConstKind::Value(_, v) => w!(cx, f, "{v:?}"),
766            ConstKind::Infer(infer_const) => w!(cx, f, "{:?}", ^infer_const),
767            ConstKind::Unevaluated(uneval_const) => w!(cx, f, "{:?}", uneval_const),
768        }
769    }
770}
771
772impl Pretty for GenericArg {
773    fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
774        match self {
775            GenericArg::Ty(ty) => w!(cx, f, "{:?}", ty),
776            GenericArg::Base(ctor) => w!(cx, f, "{:?}", ctor.to_ty()),
777            GenericArg::Lifetime(re) => w!(cx, f, "{:?}", re),
778            GenericArg::Const(c) => w!(cx, f, "{:?}", c),
779        }
780    }
781}
782
783impl Pretty for VariantSig {
784    fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
785        w!(cx, f, "({:?}) => {:?}", join!(", ", self.fields()), &self.idx)
786    }
787}
788
789impl Pretty for Region {
790    fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
791        w!(cx, f, "{}", ^region_to_string(*self))
792    }
793}
794
795impl Pretty for DebruijnIndex {
796    fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
797        w!(cx, f, "^{}", ^self.as_usize())
798    }
799}
800
801impl_debug_with_default_cx!(
802    Ensures,
803    Sort,
804    Ty => "ty",
805    BaseTy,
806    FnSig,
807    GenericArg => "generic_arg",
808    VariantSig,
809    PtrKind,
810    FuncSort,
811    SortCtor,
812    SubsetTy,
813    BvSize,
814    ExistentialPredicate,
815);
816
817impl PrettyNested for SubsetTy {
818    fn fmt_nested(&self, cx: &PrettyCx) -> Result<NestedString, fmt::Error> {
819        let bty_d = self.bty.fmt_nested(cx)?;
820        let idx_d = IdxFmt(self.idx.clone()).fmt_nested(cx)?;
821        if self.pred.is_trivially_true() || matches!(self.pred.kind(), ExprKind::KVar(..)) {
822            let text = format!("{}{}", bty_d.text, idx_d.text);
823            let children = float_children(vec![bty_d.children, idx_d.children]);
824            Ok(NestedString { text, children, key: None })
825        } else {
826            let pred_d = self.pred.fmt_nested(cx)?;
827            let text = format!("{{ {}{} | {} }}", bty_d.text, idx_d.text, pred_d.text);
828            let children = float_children(vec![bty_d.children, idx_d.children, pred_d.children]);
829            Ok(NestedString { text, children, key: None })
830        }
831    }
832}
833
834impl PrettyNested for GenericArg {
835    fn fmt_nested(&self, cx: &PrettyCx) -> Result<NestedString, fmt::Error> {
836        match self {
837            GenericArg::Ty(ty) => ty.fmt_nested(cx),
838            GenericArg::Base(ctor) => {
839                // if ctor is of the form `λb. bty[b]`, just print the `bty`
840                let inner = ctor.as_ref().skip_binder();
841                if ctor.vars().len() == 1 && inner.pred.is_trivially_true() && inner.idx.is_nu() {
842                    inner.bty.fmt_nested(cx)
843                } else {
844                    cx.nested_with_bound_vars("λ", ctor.vars(), None, |prefix| {
845                        let ctor_d = ctor.skip_binder_ref().fmt_nested(cx)?;
846                        let text = format!("{}{}", prefix, ctor_d.text);
847                        Ok(NestedString { text, children: ctor_d.children, key: None })
848                    })
849                }
850            }
851            GenericArg::Lifetime(..) | GenericArg::Const(..) => debug_nested(cx, self),
852        }
853    }
854}
855
856impl PrettyNested for BaseTy {
857    fn fmt_nested(&self, cx: &PrettyCx) -> Result<NestedString, fmt::Error> {
858        match self {
859            BaseTy::Int(..)
860            | BaseTy::Uint(..)
861            | BaseTy::Bool
862            | BaseTy::Str
863            | BaseTy::Char
864            | BaseTy::Float(..)
865            | BaseTy::Param(..)
866            | BaseTy::Never
867            | BaseTy::FnPtr(..)
868            | BaseTy::FnDef(..)
869            | BaseTy::Alias(..)
870            | BaseTy::Closure(..)
871            | BaseTy::Coroutine(..)
872            | BaseTy::Dynamic(..)
873            | BaseTy::Infer(..)
874            | BaseTy::Foreign(..) => {
875                let text = format_cx!(cx, "{:?}", self);
876                Ok(NestedString { text, children: None, key: None })
877            }
878            BaseTy::Slice(ty) => {
879                let ty_d = ty.fmt_nested(cx)?;
880                let text = format!("[{}]", ty_d.text);
881                Ok(NestedString { text, children: ty_d.children, key: None })
882            }
883            BaseTy::Array(ty, c) => {
884                let ty_d = ty.fmt_nested(cx)?;
885                let text = format_cx!(cx, "[{:?}; {:?}]", ty_d.text, c);
886                Ok(NestedString { text, children: ty_d.children, key: None })
887            }
888            BaseTy::RawPtr(ty, Mutability::Mut) => {
889                let ty_d = ty.fmt_nested(cx)?;
890                let text = format!("*mut {}", ty_d.text);
891                Ok(NestedString { text, children: ty_d.children, key: None })
892            }
893            BaseTy::RawPtr(ty, Mutability::Not) => {
894                let ty_d = ty.fmt_nested(cx)?;
895                let text = format!("*const {}", ty_d.text);
896                Ok(NestedString { text, children: ty_d.children, key: None })
897            }
898            BaseTy::RawPtrMetadata(ty) => {
899                let ty_d = ty.fmt_nested(cx)?;
900                let text = format!("*raw {}", ty_d.text);
901                Ok(NestedString { text, children: ty_d.children, key: None })
902            }
903            BaseTy::Ref(_, ty, mutbl) => {
904                let ty_d = ty.fmt_nested(cx)?;
905                let prefix = mutbl.prefix_str();
906                let text = if prefix.is_empty() {
907                    format!("&{}", ty_d.text)
908                } else {
909                    format!("&{} {}", prefix, ty_d.text)
910                };
911                Ok(NestedString { text, children: ty_d.children, key: None })
912            }
913            BaseTy::Tuple(tys) => {
914                let mut texts = vec![];
915                let mut kidss = vec![];
916                for ty in tys {
917                    let ty_d = ty.fmt_nested(cx)?;
918                    texts.push(ty_d.text);
919                    kidss.push(ty_d.children);
920                }
921                let text = if let [text] = &texts[..] {
922                    format!("({text},)")
923                } else {
924                    format!("({})", texts.join(", "))
925                };
926                let children = float_children(kidss);
927                Ok(NestedString { text, children, key: None })
928            }
929            BaseTy::Adt(adt_def, args) => {
930                let mut texts = vec![];
931                let mut kidss = vec![];
932                for arg in args {
933                    let arg_d = arg.fmt_nested(cx)?;
934                    texts.push(arg_d.text);
935                    kidss.push(arg_d.children);
936                }
937                let args_str = if !args.is_empty() {
938                    format!("<{}>", texts.join(", "))
939                } else {
940                    String::new()
941                };
942                let text = format_cx!(cx, "{:?}{:?}", adt_def.did(), args_str);
943                let children = float_children(kidss);
944                Ok(NestedString { text, children, key: None })
945            }
946            BaseTy::Pat => todo!(),
947        }
948    }
949}
950
951impl PrettyNested for Ty {
952    fn fmt_nested(&self, cx: &PrettyCx) -> Result<NestedString, fmt::Error> {
953        match self.kind() {
954            TyKind::Indexed(bty, idx) => {
955                let bty_d = bty.fmt_nested(cx)?;
956                let idx_d = IdxFmt(idx.clone()).fmt_nested(cx)?;
957                let text = if idx_d.text.is_empty() {
958                    bty_d.text
959                } else {
960                    format!("{}{}", bty_d.text, idx_d.text)
961                };
962                let children = float_children(vec![bty_d.children, idx_d.children]);
963                Ok(NestedString { text, children, key: None })
964            }
965            TyKind::Exists(ty_ctor) => {
966                // TODO: remove redundant vars; see Ty
967                // if ctor is of the form `∃b. bty[b]`, just print the `bty`
968                if ty_ctor.vars().len() == 1
969                    && let TyKind::Indexed(bty, idx) = ty_ctor.skip_binder_ref().kind()
970                    && idx.is_nu()
971                {
972                    bty.fmt_nested(cx)
973                } else {
974                    cx.nested_with_bound_vars("∃", ty_ctor.vars(), None, |exi_str| {
975                        let ty_ctor_d = ty_ctor.skip_binder_ref().fmt_nested(cx)?;
976                        let text = format!("{}{}", exi_str, ty_ctor_d.text);
977                        Ok(NestedString { text, children: ty_ctor_d.children, key: None })
978                    })
979                }
980            }
981            TyKind::Constr(expr, ty) => {
982                let expr_d = expr.fmt_nested(cx)?;
983                let ty_d = ty.fmt_nested(cx)?;
984                let text = format!("{{ {} | {} }}", ty_d.text, expr_d.text);
985                let children = float_children(vec![expr_d.children, ty_d.children]);
986                Ok(NestedString { text, children, key: None })
987            }
988            TyKind::StrgRef(re, loc, ty) => {
989                let ty_d = ty.fmt_nested(cx)?;
990                let text = if cx.hide_regions {
991                    format!("{:?}: &strg {}", loc, ty_d.text)
992                } else {
993                    format!("{:?}: &{:?} strg {}", loc, re, ty_d.text)
994                };
995                Ok(NestedString { text, children: ty_d.children, key: None })
996            }
997            TyKind::Blocked(ty) => {
998                let ty_d = ty.fmt_nested(cx)?;
999                let text = format!("†{}", ty_d.text);
1000                Ok(NestedString { text, children: ty_d.children, key: None })
1001            }
1002            TyKind::Downcast(adt, .., variant_idx, fields) => {
1003                let is_struct = adt.is_struct();
1004                let mut text = format_cx!(cx, "{:?}", adt.did());
1005                if !is_struct {
1006                    text.push_str(&format!("::{}", adt.variant(*variant_idx).name));
1007                }
1008                if is_struct {
1009                    text.push_str("{..}");
1010                } else {
1011                    text.push_str("(..)");
1012                }
1013                let keys: Vec<String> = if is_struct {
1014                    adt.variant(*variant_idx)
1015                        .fields
1016                        .iter()
1017                        .map(|f| f.name.to_string())
1018                        .collect()
1019                } else {
1020                    (0..fields.len()).map(|i| format!("{i}")).collect()
1021                };
1022                let mut children = vec![];
1023                for (key, field) in keys.into_iter().zip(fields) {
1024                    let field_d = field.fmt_nested(cx)?;
1025                    children.push(NestedString { key: Some(key), ..field_d });
1026                }
1027                Ok(NestedString { text, children: Some(children), key: None })
1028            }
1029            TyKind::Param(..)
1030            | TyKind::Uninit
1031            | TyKind::Ptr(..)
1032            | TyKind::Discr(..)
1033            | TyKind::Infer(..) => {
1034                let text = format!("{self:?}");
1035                Ok(NestedString { text, children: None, key: None })
1036            }
1037        }
1038    }
1039}