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