]> git.lizzy.rs Git - rust.git/blob - crates/hir_def/src/type_ref.rs
Merge #8186
[rust.git] / crates / hir_def / src / type_ref.rs
1 //! HIR for references to types. Paths in these are not yet resolved. They can
2 //! be directly created from an ast::TypeRef, without further queries.
3 use hir_expand::name::Name;
4 use syntax::ast;
5
6 use crate::{body::LowerCtx, path::Path};
7
8 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
9 pub enum Mutability {
10     Shared,
11     Mut,
12 }
13
14 impl Mutability {
15     pub fn from_mutable(mutable: bool) -> Mutability {
16         if mutable {
17             Mutability::Mut
18         } else {
19             Mutability::Shared
20         }
21     }
22
23     pub fn as_keyword_for_ref(self) -> &'static str {
24         match self {
25             Mutability::Shared => "",
26             Mutability::Mut => "mut ",
27         }
28     }
29
30     pub fn as_keyword_for_ptr(self) -> &'static str {
31         match self {
32             Mutability::Shared => "const ",
33             Mutability::Mut => "mut ",
34         }
35     }
36 }
37
38 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
39 pub enum Rawness {
40     RawPtr,
41     Ref,
42 }
43
44 impl Rawness {
45     pub fn from_raw(is_raw: bool) -> Rawness {
46         if is_raw {
47             Rawness::RawPtr
48         } else {
49             Rawness::Ref
50         }
51     }
52 }
53
54 #[derive(Clone, PartialEq, Eq, Hash, Debug)]
55 pub struct TraitRef {
56     pub path: Path,
57 }
58
59 impl TraitRef {
60     /// Converts an `ast::PathType` to a `hir::TraitRef`.
61     pub(crate) fn from_ast(ctx: &LowerCtx, node: ast::Type) -> Option<Self> {
62         // FIXME: Use `Path::from_src`
63         match node {
64             ast::Type::PathType(path) => {
65                 path.path().and_then(|it| ctx.lower_path(it)).map(|path| TraitRef { path })
66             }
67             _ => None,
68         }
69     }
70 }
71 /// Compare ty::Ty
72 #[derive(Clone, PartialEq, Eq, Hash, Debug)]
73 pub enum TypeRef {
74     Never,
75     Placeholder,
76     Tuple(Vec<TypeRef>),
77     Path(Path),
78     RawPtr(Box<TypeRef>, Mutability),
79     Reference(Box<TypeRef>, Option<LifetimeRef>, Mutability),
80     Array(Box<TypeRef> /*, Expr*/),
81     Slice(Box<TypeRef>),
82     /// A fn pointer. Last element of the vector is the return type.
83     Fn(Vec<TypeRef>, bool /*varargs*/),
84     // For
85     ImplTrait(Vec<TypeBound>),
86     DynTrait(Vec<TypeBound>),
87     Error,
88 }
89
90 #[derive(Clone, PartialEq, Eq, Hash, Debug)]
91 pub struct LifetimeRef {
92     pub name: Name,
93 }
94
95 impl LifetimeRef {
96     pub(crate) fn new_name(name: Name) -> Self {
97         LifetimeRef { name }
98     }
99
100     pub(crate) fn new(lifetime: &ast::Lifetime) -> Self {
101         LifetimeRef { name: Name::new_lifetime(lifetime) }
102     }
103
104     pub fn missing() -> LifetimeRef {
105         LifetimeRef { name: Name::missing() }
106     }
107 }
108
109 #[derive(Clone, PartialEq, Eq, Hash, Debug)]
110 pub enum TypeBound {
111     Path(Path),
112     // ForLifetime(Vec<LifetimeRef>, Path), FIXME ForLifetime
113     Lifetime(LifetimeRef),
114     Error,
115 }
116
117 impl TypeRef {
118     /// Converts an `ast::TypeRef` to a `hir::TypeRef`.
119     pub(crate) fn from_ast(ctx: &LowerCtx, node: ast::Type) -> Self {
120         match node {
121             ast::Type::ParenType(inner) => TypeRef::from_ast_opt(&ctx, inner.ty()),
122             ast::Type::TupleType(inner) => {
123                 TypeRef::Tuple(inner.fields().map(|it| TypeRef::from_ast(ctx, it)).collect())
124             }
125             ast::Type::NeverType(..) => TypeRef::Never,
126             ast::Type::PathType(inner) => {
127                 // FIXME: Use `Path::from_src`
128                 inner
129                     .path()
130                     .and_then(|it| ctx.lower_path(it))
131                     .map(TypeRef::Path)
132                     .unwrap_or(TypeRef::Error)
133             }
134             ast::Type::PtrType(inner) => {
135                 let inner_ty = TypeRef::from_ast_opt(&ctx, inner.ty());
136                 let mutability = Mutability::from_mutable(inner.mut_token().is_some());
137                 TypeRef::RawPtr(Box::new(inner_ty), mutability)
138             }
139             ast::Type::ArrayType(inner) => {
140                 TypeRef::Array(Box::new(TypeRef::from_ast_opt(&ctx, inner.ty())))
141             }
142             ast::Type::SliceType(inner) => {
143                 TypeRef::Slice(Box::new(TypeRef::from_ast_opt(&ctx, inner.ty())))
144             }
145             ast::Type::RefType(inner) => {
146                 let inner_ty = TypeRef::from_ast_opt(&ctx, inner.ty());
147                 let lifetime = inner.lifetime().map(|lt| LifetimeRef::new(&lt));
148                 let mutability = Mutability::from_mutable(inner.mut_token().is_some());
149                 TypeRef::Reference(Box::new(inner_ty), lifetime, mutability)
150             }
151             ast::Type::InferType(_inner) => TypeRef::Placeholder,
152             ast::Type::FnPtrType(inner) => {
153                 let ret_ty = inner
154                     .ret_type()
155                     .and_then(|rt| rt.ty())
156                     .map(|it| TypeRef::from_ast(ctx, it))
157                     .unwrap_or_else(|| TypeRef::Tuple(Vec::new()));
158                 let mut is_varargs = false;
159                 let mut params = if let Some(pl) = inner.param_list() {
160                     if let Some(param) = pl.params().last() {
161                         is_varargs = param.dotdotdot_token().is_some();
162                     }
163
164                     pl.params().map(|p| p.ty()).map(|it| TypeRef::from_ast_opt(&ctx, it)).collect()
165                 } else {
166                     Vec::new()
167                 };
168                 params.push(ret_ty);
169                 TypeRef::Fn(params, is_varargs)
170             }
171             // for types are close enough for our purposes to the inner type for now...
172             ast::Type::ForType(inner) => TypeRef::from_ast_opt(&ctx, inner.ty()),
173             ast::Type::ImplTraitType(inner) => {
174                 TypeRef::ImplTrait(type_bounds_from_ast(ctx, inner.type_bound_list()))
175             }
176             ast::Type::DynTraitType(inner) => {
177                 TypeRef::DynTrait(type_bounds_from_ast(ctx, inner.type_bound_list()))
178             }
179             // FIXME: Macros in type position are not yet supported.
180             ast::Type::MacroType(_) => TypeRef::Error,
181         }
182     }
183
184     pub(crate) fn from_ast_opt(ctx: &LowerCtx, node: Option<ast::Type>) -> Self {
185         if let Some(node) = node {
186             TypeRef::from_ast(ctx, node)
187         } else {
188             TypeRef::Error
189         }
190     }
191
192     pub(crate) fn unit() -> TypeRef {
193         TypeRef::Tuple(Vec::new())
194     }
195
196     pub fn walk(&self, f: &mut impl FnMut(&TypeRef)) {
197         go(self, f);
198
199         fn go(type_ref: &TypeRef, f: &mut impl FnMut(&TypeRef)) {
200             f(type_ref);
201             match type_ref {
202                 TypeRef::Fn(types, _) | TypeRef::Tuple(types) => {
203                     types.iter().for_each(|t| go(t, f))
204                 }
205                 TypeRef::RawPtr(type_ref, _)
206                 | TypeRef::Reference(type_ref, ..)
207                 | TypeRef::Array(type_ref)
208                 | TypeRef::Slice(type_ref) => go(&type_ref, f),
209                 TypeRef::ImplTrait(bounds) | TypeRef::DynTrait(bounds) => {
210                     for bound in bounds {
211                         match bound {
212                             TypeBound::Path(path) => go_path(path, f),
213                             TypeBound::Lifetime(_) | TypeBound::Error => (),
214                         }
215                     }
216                 }
217                 TypeRef::Path(path) => go_path(path, f),
218                 TypeRef::Never | TypeRef::Placeholder | TypeRef::Error => {}
219             };
220         }
221
222         fn go_path(path: &Path, f: &mut impl FnMut(&TypeRef)) {
223             if let Some(type_ref) = path.type_anchor() {
224                 go(type_ref, f);
225             }
226             for segment in path.segments().iter() {
227                 if let Some(args_and_bindings) = segment.args_and_bindings {
228                     for arg in &args_and_bindings.args {
229                         match arg {
230                             crate::path::GenericArg::Type(type_ref) => {
231                                 go(type_ref, f);
232                             }
233                             crate::path::GenericArg::Lifetime(_) => {}
234                         }
235                     }
236                     for binding in &args_and_bindings.bindings {
237                         if let Some(type_ref) = &binding.type_ref {
238                             go(type_ref, f);
239                         }
240                         for bound in &binding.bounds {
241                             match bound {
242                                 TypeBound::Path(path) => go_path(path, f),
243                                 TypeBound::Lifetime(_) | TypeBound::Error => (),
244                             }
245                         }
246                     }
247                 }
248             }
249         }
250     }
251 }
252
253 pub(crate) fn type_bounds_from_ast(
254     lower_ctx: &LowerCtx,
255     type_bounds_opt: Option<ast::TypeBoundList>,
256 ) -> Vec<TypeBound> {
257     if let Some(type_bounds) = type_bounds_opt {
258         type_bounds.bounds().map(|it| TypeBound::from_ast(lower_ctx, it)).collect()
259     } else {
260         vec![]
261     }
262 }
263
264 impl TypeBound {
265     pub(crate) fn from_ast(ctx: &LowerCtx, node: ast::TypeBound) -> Self {
266         match node.kind() {
267             ast::TypeBoundKind::PathType(path_type) => {
268                 let path = match path_type.path() {
269                     Some(p) => p,
270                     None => return TypeBound::Error,
271                 };
272
273                 let path = match ctx.lower_path(path) {
274                     Some(p) => p,
275                     None => return TypeBound::Error,
276                 };
277                 TypeBound::Path(path)
278             }
279             ast::TypeBoundKind::ForType(_) => TypeBound::Error, // FIXME ForType
280             ast::TypeBoundKind::Lifetime(lifetime) => {
281                 TypeBound::Lifetime(LifetimeRef::new(&lifetime))
282             }
283         }
284     }
285
286     pub fn as_path(&self) -> Option<&Path> {
287         match self {
288             TypeBound::Path(p) => Some(p),
289             _ => None,
290         }
291     }
292 }