]> git.lizzy.rs Git - rust.git/blob - crates/hir_def/src/type_ref.rs
Add `MacroType` syntax
[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 /// Compare ty::Ty
55 #[derive(Clone, PartialEq, Eq, Hash, Debug)]
56 pub enum TypeRef {
57     Never,
58     Placeholder,
59     Tuple(Vec<TypeRef>),
60     Path(Path),
61     RawPtr(Box<TypeRef>, Mutability),
62     Reference(Box<TypeRef>, Option<LifetimeRef>, Mutability),
63     Array(Box<TypeRef> /*, Expr*/),
64     Slice(Box<TypeRef>),
65     /// A fn pointer. Last element of the vector is the return type.
66     Fn(Vec<TypeRef>, bool /*varargs*/),
67     // For
68     ImplTrait(Vec<TypeBound>),
69     DynTrait(Vec<TypeBound>),
70     Error,
71 }
72
73 #[derive(Clone, PartialEq, Eq, Hash, Debug)]
74 pub struct LifetimeRef {
75     pub name: Name,
76 }
77
78 impl LifetimeRef {
79     pub(crate) fn new_name(name: Name) -> Self {
80         LifetimeRef { name }
81     }
82
83     pub(crate) fn new(lifetime: &ast::Lifetime) -> Self {
84         LifetimeRef { name: Name::new_lifetime(lifetime) }
85     }
86
87     pub fn missing() -> LifetimeRef {
88         LifetimeRef { name: Name::missing() }
89     }
90 }
91
92 #[derive(Clone, PartialEq, Eq, Hash, Debug)]
93 pub enum TypeBound {
94     Path(Path),
95     // ForLifetime(Vec<LifetimeRef>, Path), FIXME ForLifetime
96     Lifetime(LifetimeRef),
97     Error,
98 }
99
100 impl TypeRef {
101     /// Converts an `ast::TypeRef` to a `hir::TypeRef`.
102     pub(crate) fn from_ast(ctx: &LowerCtx, node: ast::Type) -> Self {
103         match node {
104             ast::Type::ParenType(inner) => TypeRef::from_ast_opt(&ctx, inner.ty()),
105             ast::Type::TupleType(inner) => {
106                 TypeRef::Tuple(inner.fields().map(|it| TypeRef::from_ast(ctx, it)).collect())
107             }
108             ast::Type::NeverType(..) => TypeRef::Never,
109             ast::Type::PathType(inner) => {
110                 // FIXME: Use `Path::from_src`
111                 inner
112                     .path()
113                     .and_then(|it| ctx.lower_path(it))
114                     .map(TypeRef::Path)
115                     .unwrap_or(TypeRef::Error)
116             }
117             ast::Type::PtrType(inner) => {
118                 let inner_ty = TypeRef::from_ast_opt(&ctx, inner.ty());
119                 let mutability = Mutability::from_mutable(inner.mut_token().is_some());
120                 TypeRef::RawPtr(Box::new(inner_ty), mutability)
121             }
122             ast::Type::ArrayType(inner) => {
123                 TypeRef::Array(Box::new(TypeRef::from_ast_opt(&ctx, inner.ty())))
124             }
125             ast::Type::SliceType(inner) => {
126                 TypeRef::Slice(Box::new(TypeRef::from_ast_opt(&ctx, inner.ty())))
127             }
128             ast::Type::RefType(inner) => {
129                 let inner_ty = TypeRef::from_ast_opt(&ctx, inner.ty());
130                 let lifetime = inner.lifetime().map(|lt| LifetimeRef::new(&lt));
131                 let mutability = Mutability::from_mutable(inner.mut_token().is_some());
132                 TypeRef::Reference(Box::new(inner_ty), lifetime, mutability)
133             }
134             ast::Type::InferType(_inner) => TypeRef::Placeholder,
135             ast::Type::FnPtrType(inner) => {
136                 let ret_ty = inner
137                     .ret_type()
138                     .and_then(|rt| rt.ty())
139                     .map(|it| TypeRef::from_ast(ctx, it))
140                     .unwrap_or_else(|| TypeRef::Tuple(Vec::new()));
141                 let mut is_varargs = false;
142                 let mut params = if let Some(pl) = inner.param_list() {
143                     if let Some(param) = pl.params().last() {
144                         is_varargs = param.dotdotdot_token().is_some();
145                     }
146
147                     pl.params().map(|p| p.ty()).map(|it| TypeRef::from_ast_opt(&ctx, it)).collect()
148                 } else {
149                     Vec::new()
150                 };
151                 params.push(ret_ty);
152                 TypeRef::Fn(params, is_varargs)
153             }
154             // for types are close enough for our purposes to the inner type for now...
155             ast::Type::ForType(inner) => TypeRef::from_ast_opt(&ctx, inner.ty()),
156             ast::Type::ImplTraitType(inner) => {
157                 TypeRef::ImplTrait(type_bounds_from_ast(ctx, inner.type_bound_list()))
158             }
159             ast::Type::DynTraitType(inner) => {
160                 TypeRef::DynTrait(type_bounds_from_ast(ctx, inner.type_bound_list()))
161             }
162             // FIXME: Macros in type position are not yet supported.
163             ast::Type::MacroType(_) => TypeRef::Error,
164         }
165     }
166
167     pub(crate) fn from_ast_opt(ctx: &LowerCtx, node: Option<ast::Type>) -> Self {
168         if let Some(node) = node {
169             TypeRef::from_ast(ctx, node)
170         } else {
171             TypeRef::Error
172         }
173     }
174
175     pub(crate) fn unit() -> TypeRef {
176         TypeRef::Tuple(Vec::new())
177     }
178
179     pub fn walk(&self, f: &mut impl FnMut(&TypeRef)) {
180         go(self, f);
181
182         fn go(type_ref: &TypeRef, f: &mut impl FnMut(&TypeRef)) {
183             f(type_ref);
184             match type_ref {
185                 TypeRef::Fn(types, _) | TypeRef::Tuple(types) => {
186                     types.iter().for_each(|t| go(t, f))
187                 }
188                 TypeRef::RawPtr(type_ref, _)
189                 | TypeRef::Reference(type_ref, ..)
190                 | TypeRef::Array(type_ref)
191                 | TypeRef::Slice(type_ref) => go(&type_ref, f),
192                 TypeRef::ImplTrait(bounds) | TypeRef::DynTrait(bounds) => {
193                     for bound in bounds {
194                         match bound {
195                             TypeBound::Path(path) => go_path(path, f),
196                             TypeBound::Lifetime(_) | TypeBound::Error => (),
197                         }
198                     }
199                 }
200                 TypeRef::Path(path) => go_path(path, f),
201                 TypeRef::Never | TypeRef::Placeholder | TypeRef::Error => {}
202             };
203         }
204
205         fn go_path(path: &Path, f: &mut impl FnMut(&TypeRef)) {
206             if let Some(type_ref) = path.type_anchor() {
207                 go(type_ref, f);
208             }
209             for segment in path.segments().iter() {
210                 if let Some(args_and_bindings) = segment.args_and_bindings {
211                     for arg in &args_and_bindings.args {
212                         match arg {
213                             crate::path::GenericArg::Type(type_ref) => {
214                                 go(type_ref, f);
215                             }
216                             crate::path::GenericArg::Lifetime(_) => {}
217                         }
218                     }
219                     for binding in &args_and_bindings.bindings {
220                         if let Some(type_ref) = &binding.type_ref {
221                             go(type_ref, f);
222                         }
223                         for bound in &binding.bounds {
224                             match bound {
225                                 TypeBound::Path(path) => go_path(path, f),
226                                 TypeBound::Lifetime(_) | TypeBound::Error => (),
227                             }
228                         }
229                     }
230                 }
231             }
232         }
233     }
234 }
235
236 pub(crate) fn type_bounds_from_ast(
237     lower_ctx: &LowerCtx,
238     type_bounds_opt: Option<ast::TypeBoundList>,
239 ) -> Vec<TypeBound> {
240     if let Some(type_bounds) = type_bounds_opt {
241         type_bounds.bounds().map(|it| TypeBound::from_ast(lower_ctx, it)).collect()
242     } else {
243         vec![]
244     }
245 }
246
247 impl TypeBound {
248     pub(crate) fn from_ast(ctx: &LowerCtx, node: ast::TypeBound) -> Self {
249         match node.kind() {
250             ast::TypeBoundKind::PathType(path_type) => {
251                 let path = match path_type.path() {
252                     Some(p) => p,
253                     None => return TypeBound::Error,
254                 };
255
256                 let path = match ctx.lower_path(path) {
257                     Some(p) => p,
258                     None => return TypeBound::Error,
259                 };
260                 TypeBound::Path(path)
261             }
262             ast::TypeBoundKind::ForType(_) => TypeBound::Error, // FIXME ForType
263             ast::TypeBoundKind::Lifetime(lifetime) => {
264                 TypeBound::Lifetime(LifetimeRef::new(&lifetime))
265             }
266         }
267     }
268
269     pub fn as_path(&self) -> Option<&Path> {
270         match self {
271             TypeBound::Path(p) => Some(p),
272             _ => None,
273         }
274     }
275 }