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