aboutsummaryrefslogtreecommitdiff
path: root/crates/hir
diff options
context:
space:
mode:
Diffstat (limited to 'crates/hir')
-rw-r--r--crates/hir/src/display.rs234
-rw-r--r--crates/hir/src/lib.rs17
2 files changed, 247 insertions, 4 deletions
diff --git a/crates/hir/src/display.rs b/crates/hir/src/display.rs
index 86f48256e..ae08e2584 100644
--- a/crates/hir/src/display.rs
+++ b/crates/hir/src/display.rs
@@ -1,9 +1,120 @@
1//! HirDisplay implementations for various hir types. 1//! HirDisplay implementations for various hir types.
2use hir_def::{
3 generics::{TypeParamProvenance, WherePredicate, WherePredicateTypeTarget},
4 type_ref::{TypeBound, TypeRef},
5 GenericDefId,
6};
2use hir_ty::display::{ 7use hir_ty::display::{
3 write_bounds_like_dyn_trait_with_prefix, HirDisplay, HirDisplayError, HirFormatter, 8 write_bounds_like_dyn_trait_with_prefix, write_visibility, HirDisplay, HirDisplayError,
9 HirFormatter,
4}; 10};
11use syntax::ast::{self, NameOwner};
12
13use crate::{Function, HasVisibility, Substs, Type, TypeParam};
14
15impl HirDisplay for Function {
16 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
17 let data = f.db.function_data(self.id);
18 write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
19 let qual = &data.qualifier;
20 if qual.is_default {
21 write!(f, "default ")?;
22 }
23 if qual.is_const {
24 write!(f, "const ")?;
25 }
26 if qual.is_async {
27 write!(f, "async ")?;
28 }
29 if qual.is_unsafe {
30 write!(f, "unsafe ")?;
31 }
32 if let Some(abi) = &qual.abi {
33 // FIXME: String escape?
34 write!(f, "extern \"{}\" ", abi)?;
35 }
36 write!(f, "fn {}", data.name)?;
37
38 write_generic_params(GenericDefId::FunctionId(self.id), f)?;
39
40 write!(f, "(")?;
5 41
6use crate::{Substs, Type, TypeParam}; 42 let write_self_param = |ty: &TypeRef, f: &mut HirFormatter| match ty {
43 TypeRef::Path(p) if p.is_self_type() => write!(f, "self"),
44 TypeRef::Reference(inner, lifetime, mut_) if matches!(&**inner,TypeRef::Path(p) if p.is_self_type()) =>
45 {
46 write!(f, "&")?;
47 if let Some(lifetime) = lifetime {
48 write!(f, "{} ", lifetime.name)?;
49 }
50 if let hir_def::type_ref::Mutability::Mut = mut_ {
51 write!(f, "mut ")?;
52 }
53 write!(f, "self")
54 }
55 _ => {
56 write!(f, "self: ")?;
57 ty.hir_fmt(f)
58 }
59 };
60
61 let mut first = true;
62 for (param, type_ref) in self.assoc_fn_params(f.db).into_iter().zip(&data.params) {
63 if !first {
64 write!(f, ", ")?;
65 } else {
66 first = false;
67 if data.has_self_param {
68 write_self_param(type_ref, f)?;
69 continue;
70 }
71 }
72 match param.pattern_source(f.db) {
73 Some(ast::Pat::IdentPat(p)) if p.name().is_some() => {
74 write!(f, "{}: ", p.name().unwrap())?
75 }
76 _ => write!(f, "_: ")?,
77 }
78 // FIXME: Use resolved `param.ty` or raw `type_ref`?
79 // The former will ignore lifetime arguments currently.
80 type_ref.hir_fmt(f)?;
81 }
82 write!(f, ")")?;
83
84 // `FunctionData::ret_type` will be `::core::future::Future<Output = ...>` for async fns.
85 // Use ugly pattern match to strip the Future trait.
86 // Better way?
87 let ret_type = if !qual.is_async {
88 &data.ret_type
89 } else {
90 match &data.ret_type {
91 TypeRef::ImplTrait(bounds) => match &bounds[0] {
92 TypeBound::Path(path) => {
93 path.segments().iter().last().unwrap().args_and_bindings.unwrap().bindings
94 [0]
95 .type_ref
96 .as_ref()
97 .unwrap()
98 }
99 _ => panic!("Async fn ret_type should be impl Future"),
100 },
101 _ => panic!("Async fn ret_type should be impl Future"),
102 }
103 };
104
105 match ret_type {
106 TypeRef::Tuple(tup) if tup.is_empty() => {}
107 ty => {
108 write!(f, " -> ")?;
109 ty.hir_fmt(f)?;
110 }
111 }
112
113 write_where_clause(GenericDefId::FunctionId(self.id), f)?;
114
115 Ok(())
116 }
117}
7 118
8impl HirDisplay for Type { 119impl HirDisplay for Type {
9 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> { 120 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
@@ -23,3 +134,122 @@ impl HirDisplay for TypeParam {
23 Ok(()) 134 Ok(())
24 } 135 }
25} 136}
137
138fn write_generic_params(def: GenericDefId, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
139 let params = f.db.generic_params(def);
140 if params.lifetimes.is_empty() && params.types.is_empty() && params.consts.is_empty() {
141 return Ok(());
142 }
143 write!(f, "<")?;
144
145 let mut first = true;
146 let mut delim = |f: &mut HirFormatter| {
147 if first {
148 first = false;
149 Ok(())
150 } else {
151 write!(f, ", ")
152 }
153 };
154 for (_, lifetime) in params.lifetimes.iter() {
155 delim(f)?;
156 write!(f, "{}", lifetime.name)?;
157 }
158 for (_, ty) in params.types.iter() {
159 if ty.provenance != TypeParamProvenance::TypeParamList {
160 continue;
161 }
162 if let Some(name) = &ty.name {
163 delim(f)?;
164 write!(f, "{}", name)?;
165 if let Some(default) = &ty.default {
166 write!(f, " = ")?;
167 default.hir_fmt(f)?;
168 }
169 }
170 }
171 for (_, konst) in params.consts.iter() {
172 delim(f)?;
173 write!(f, "const {}: ", konst.name)?;
174 konst.ty.hir_fmt(f)?;
175 }
176
177 write!(f, ">")?;
178 Ok(())
179}
180
181fn write_where_clause(def: GenericDefId, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
182 let params = f.db.generic_params(def);
183 if params.where_predicates.is_empty() {
184 return Ok(());
185 }
186
187 let write_target = |target: &WherePredicateTypeTarget, f: &mut HirFormatter| match target {
188 WherePredicateTypeTarget::TypeRef(ty) => ty.hir_fmt(f),
189 WherePredicateTypeTarget::TypeParam(id) => match &params.types[*id].name {
190 Some(name) => write!(f, "{}", name),
191 None => write!(f, "{{unnamed}}"),
192 },
193 };
194
195 write!(f, "\nwhere")?;
196
197 for (pred_idx, pred) in params.where_predicates.iter().enumerate() {
198 let prev_pred =
199 if pred_idx == 0 { None } else { Some(&params.where_predicates[pred_idx - 1]) };
200
201 let new_predicate = |f: &mut HirFormatter| {
202 write!(f, "{}", if pred_idx == 0 { "\n " } else { ",\n " })
203 };
204
205 match pred {
206 WherePredicate::TypeBound { target, bound } => {
207 if matches!(prev_pred, Some(WherePredicate::TypeBound { target: target_, .. }) if target_ == target)
208 {
209 write!(f, " + ")?;
210 } else {
211 new_predicate(f)?;
212 write_target(target, f)?;
213 write!(f, ": ")?;
214 }
215 bound.hir_fmt(f)?;
216 }
217 WherePredicate::Lifetime { target, bound } => {
218 if matches!(prev_pred, Some(WherePredicate::Lifetime { target: target_, .. }) if target_ == target)
219 {
220 write!(f, " + {}", bound.name)?;
221 } else {
222 new_predicate(f)?;
223 write!(f, "{}: {}", target.name, bound.name)?;
224 }
225 }
226 WherePredicate::ForLifetime { lifetimes, target, bound } => {
227 if matches!(
228 prev_pred,
229 Some(WherePredicate::ForLifetime { lifetimes: lifetimes_, target: target_, .. })
230 if lifetimes_ == lifetimes && target_ == target,
231 ) {
232 write!(f, " + ")?;
233 } else {
234 new_predicate(f)?;
235 write!(f, "for<")?;
236 for (idx, lifetime) in lifetimes.iter().enumerate() {
237 if idx != 0 {
238 write!(f, ", ")?;
239 }
240 write!(f, "{}", lifetime)?;
241 }
242 write!(f, "> ")?;
243 write_target(target, f)?;
244 write!(f, ": ")?;
245 }
246 bound.hir_fmt(f)?;
247 }
248 }
249 }
250
251 // End of final predicate. There must be at least one predicate here.
252 write!(f, ",")?;
253
254 Ok(())
255}
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 0d0e757fc..476fdb132 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -822,7 +822,8 @@ impl Function {
822 db.function_data(self.id) 822 db.function_data(self.id)
823 .params 823 .params
824 .iter() 824 .iter()
825 .map(|type_ref| { 825 .enumerate()
826 .map(|(idx, type_ref)| {
826 let ty = Type { 827 let ty = Type {
827 krate, 828 krate,
828 ty: InEnvironment { 829 ty: InEnvironment {
@@ -830,7 +831,7 @@ impl Function {
830 environment: environment.clone(), 831 environment: environment.clone(),
831 }, 832 },
832 }; 833 };
833 Param { ty } 834 Param { func: self, ty, idx }
834 }) 835 })
835 .collect() 836 .collect()
836 } 837 }
@@ -893,6 +894,9 @@ impl From<hir_ty::Mutability> for Access {
893 894
894#[derive(Debug)] 895#[derive(Debug)]
895pub struct Param { 896pub struct Param {
897 func: Function,
898 /// The index in parameter list, including self parameter.
899 idx: usize,
896 ty: Type, 900 ty: Type,
897} 901}
898 902
@@ -900,6 +904,15 @@ impl Param {
900 pub fn ty(&self) -> &Type { 904 pub fn ty(&self) -> &Type {
901 &self.ty 905 &self.ty
902 } 906 }
907
908 pub fn pattern_source(&self, db: &dyn HirDatabase) -> Option<ast::Pat> {
909 let params = self.func.source(db)?.value.param_list()?;
910 if params.self_param().is_some() {
911 params.params().nth(self.idx.checked_sub(1)?)?.pat()
912 } else {
913 params.params().nth(self.idx)?.pat()
914 }
915 }
903} 916}
904 917
905#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 918#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]