]> git.lizzy.rs Git - rust.git/blob - src/tools/rust-analyzer/crates/hir-def/src/pretty.rs
Rollup merge of #101049 - JeanCASPAR:remove-span_fatal-from-ast_lowering, r=davidtwco
[rust.git] / src / tools / rust-analyzer / crates / hir-def / src / pretty.rs
1 //! Display and pretty printing routines.
2
3 use std::fmt::{self, Write};
4
5 use hir_expand::mod_path::PathKind;
6 use itertools::Itertools;
7
8 use crate::{
9     intern::Interned,
10     path::{GenericArg, GenericArgs, Path},
11     type_ref::{Mutability, TraitBoundModifier, TypeBound, TypeRef},
12 };
13
14 pub(crate) fn print_path(path: &Path, buf: &mut dyn Write) -> fmt::Result {
15     match path.type_anchor() {
16         Some(anchor) => {
17             write!(buf, "<")?;
18             print_type_ref(anchor, buf)?;
19             write!(buf, ">::")?;
20         }
21         None => match path.kind() {
22             PathKind::Plain => {}
23             PathKind::Super(0) => write!(buf, "self")?,
24             PathKind::Super(n) => {
25                 for i in 0..*n {
26                     if i == 0 {
27                         buf.write_str("super")?;
28                     } else {
29                         buf.write_str("::super")?;
30                     }
31                 }
32             }
33             PathKind::Crate => write!(buf, "crate")?,
34             PathKind::Abs => {}
35             PathKind::DollarCrate(_) => write!(buf, "$crate")?,
36         },
37     }
38
39     for (i, segment) in path.segments().iter().enumerate() {
40         if i != 0 || !matches!(path.kind(), PathKind::Plain) {
41             write!(buf, "::")?;
42         }
43
44         write!(buf, "{}", segment.name)?;
45         if let Some(generics) = segment.args_and_bindings {
46             write!(buf, "::<")?;
47             print_generic_args(generics, buf)?;
48
49             write!(buf, ">")?;
50         }
51     }
52
53     Ok(())
54 }
55
56 pub(crate) fn print_generic_args(generics: &GenericArgs, buf: &mut dyn Write) -> fmt::Result {
57     let mut first = true;
58     let args = if generics.has_self_type {
59         let (self_ty, args) = generics.args.split_first().unwrap();
60         write!(buf, "Self=")?;
61         print_generic_arg(self_ty, buf)?;
62         first = false;
63         args
64     } else {
65         &generics.args
66     };
67     for arg in args {
68         if !first {
69             write!(buf, ", ")?;
70         }
71         first = false;
72         print_generic_arg(arg, buf)?;
73     }
74     for binding in &generics.bindings {
75         if !first {
76             write!(buf, ", ")?;
77         }
78         first = false;
79         write!(buf, "{}", binding.name)?;
80         if !binding.bounds.is_empty() {
81             write!(buf, ": ")?;
82             print_type_bounds(&binding.bounds, buf)?;
83         }
84         if let Some(ty) = &binding.type_ref {
85             write!(buf, " = ")?;
86             print_type_ref(ty, buf)?;
87         }
88     }
89     Ok(())
90 }
91
92 pub(crate) fn print_generic_arg(arg: &GenericArg, buf: &mut dyn Write) -> fmt::Result {
93     match arg {
94         GenericArg::Type(ty) => print_type_ref(ty, buf),
95         GenericArg::Const(c) => write!(buf, "{}", c),
96         GenericArg::Lifetime(lt) => write!(buf, "{}", lt.name),
97     }
98 }
99
100 pub(crate) fn print_type_ref(type_ref: &TypeRef, buf: &mut dyn Write) -> fmt::Result {
101     // FIXME: deduplicate with `HirDisplay` impl
102     match type_ref {
103         TypeRef::Never => write!(buf, "!")?,
104         TypeRef::Placeholder => write!(buf, "_")?,
105         TypeRef::Tuple(fields) => {
106             write!(buf, "(")?;
107             for (i, field) in fields.iter().enumerate() {
108                 if i != 0 {
109                     write!(buf, ", ")?;
110                 }
111                 print_type_ref(field, buf)?;
112             }
113             write!(buf, ")")?;
114         }
115         TypeRef::Path(path) => print_path(path, buf)?,
116         TypeRef::RawPtr(pointee, mtbl) => {
117             let mtbl = match mtbl {
118                 Mutability::Shared => "*const",
119                 Mutability::Mut => "*mut",
120             };
121             write!(buf, "{} ", mtbl)?;
122             print_type_ref(pointee, buf)?;
123         }
124         TypeRef::Reference(pointee, lt, mtbl) => {
125             let mtbl = match mtbl {
126                 Mutability::Shared => "",
127                 Mutability::Mut => "mut ",
128             };
129             write!(buf, "&")?;
130             if let Some(lt) = lt {
131                 write!(buf, "{} ", lt.name)?;
132             }
133             write!(buf, "{}", mtbl)?;
134             print_type_ref(pointee, buf)?;
135         }
136         TypeRef::Array(elem, len) => {
137             write!(buf, "[")?;
138             print_type_ref(elem, buf)?;
139             write!(buf, "; {}]", len)?;
140         }
141         TypeRef::Slice(elem) => {
142             write!(buf, "[")?;
143             print_type_ref(elem, buf)?;
144             write!(buf, "]")?;
145         }
146         TypeRef::Fn(args_and_ret, varargs) => {
147             let ((_, return_type), args) =
148                 args_and_ret.split_last().expect("TypeRef::Fn is missing return type");
149             write!(buf, "fn(")?;
150             for (i, (_, typeref)) in args.iter().enumerate() {
151                 if i != 0 {
152                     write!(buf, ", ")?;
153                 }
154                 print_type_ref(typeref, buf)?;
155             }
156             if *varargs {
157                 if !args.is_empty() {
158                     write!(buf, ", ")?;
159                 }
160                 write!(buf, "...")?;
161             }
162             write!(buf, ") -> ")?;
163             print_type_ref(return_type, buf)?;
164         }
165         TypeRef::Macro(_ast_id) => {
166             write!(buf, "<macro>")?;
167         }
168         TypeRef::Error => write!(buf, "{{unknown}}")?,
169         TypeRef::ImplTrait(bounds) => {
170             write!(buf, "impl ")?;
171             print_type_bounds(bounds, buf)?;
172         }
173         TypeRef::DynTrait(bounds) => {
174             write!(buf, "dyn ")?;
175             print_type_bounds(bounds, buf)?;
176         }
177     }
178
179     Ok(())
180 }
181
182 pub(crate) fn print_type_bounds(
183     bounds: &[Interned<TypeBound>],
184     buf: &mut dyn Write,
185 ) -> fmt::Result {
186     for (i, bound) in bounds.iter().enumerate() {
187         if i != 0 {
188             write!(buf, " + ")?;
189         }
190
191         match bound.as_ref() {
192             TypeBound::Path(path, modifier) => {
193                 match modifier {
194                     TraitBoundModifier::None => (),
195                     TraitBoundModifier::Maybe => write!(buf, "?")?,
196                 }
197                 print_path(path, buf)?;
198             }
199             TypeBound::ForLifetime(lifetimes, path) => {
200                 write!(buf, "for<{}> ", lifetimes.iter().format(", "))?;
201                 print_path(path, buf)?;
202             }
203             TypeBound::Lifetime(lt) => write!(buf, "{}", lt.name)?,
204             TypeBound::Error => write!(buf, "{{unknown}}")?,
205         }
206     }
207
208     Ok(())
209 }