]> git.proxmox.com Git - rustc.git/blob - src/tools/rust-analyzer/crates/hir-def/src/pretty.rs
New upstream version 1.69.0+dfsg1
[rustc.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 intern::Interned;
7 use itertools::Itertools;
8
9 use crate::{
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.iter() {
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, is_unsafe) => {
147 let ((_, return_type), args) =
148 args_and_ret.split_last().expect("TypeRef::Fn is missing return type");
149 if *is_unsafe {
150 write!(buf, "unsafe ")?;
151 }
152 write!(buf, "fn(")?;
153 for (i, (_, typeref)) in args.iter().enumerate() {
154 if i != 0 {
155 write!(buf, ", ")?;
156 }
157 print_type_ref(typeref, buf)?;
158 }
159 if *varargs {
160 if !args.is_empty() {
161 write!(buf, ", ")?;
162 }
163 write!(buf, "...")?;
164 }
165 write!(buf, ") -> ")?;
166 print_type_ref(return_type, buf)?;
167 }
168 TypeRef::Macro(_ast_id) => {
169 write!(buf, "<macro>")?;
170 }
171 TypeRef::Error => write!(buf, "{{unknown}}")?,
172 TypeRef::ImplTrait(bounds) => {
173 write!(buf, "impl ")?;
174 print_type_bounds(bounds, buf)?;
175 }
176 TypeRef::DynTrait(bounds) => {
177 write!(buf, "dyn ")?;
178 print_type_bounds(bounds, buf)?;
179 }
180 }
181
182 Ok(())
183 }
184
185 pub(crate) fn print_type_bounds(
186 bounds: &[Interned<TypeBound>],
187 buf: &mut dyn Write,
188 ) -> fmt::Result {
189 for (i, bound) in bounds.iter().enumerate() {
190 if i != 0 {
191 write!(buf, " + ")?;
192 }
193
194 match bound.as_ref() {
195 TypeBound::Path(path, modifier) => {
196 match modifier {
197 TraitBoundModifier::None => (),
198 TraitBoundModifier::Maybe => write!(buf, "?")?,
199 }
200 print_path(path, buf)?;
201 }
202 TypeBound::ForLifetime(lifetimes, path) => {
203 write!(buf, "for<{}> ", lifetimes.iter().format(", "))?;
204 print_path(path, buf)?;
205 }
206 TypeBound::Lifetime(lt) => write!(buf, "{}", lt.name)?,
207 TypeBound::Error => write!(buf, "{{unknown}}")?,
208 }
209 }
210
211 Ok(())
212 }