diff options
author | Aleksey Kladov <[email protected]> | 2020-08-13 15:28:27 +0100 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2020-08-13 15:29:33 +0100 |
commit | b28c54a2c239acd73f2eea80fda9ee3960d2c046 (patch) | |
tree | 1bf0ea193bdb3b16ff42c2c01118b13a4276b2bb /crates/hir_def/src/type_ref.rs | |
parent | b7aa4898e0841ab8199643f89a0caa967b698ca8 (diff) |
Rename ra_hir_def -> hir_def
Diffstat (limited to 'crates/hir_def/src/type_ref.rs')
-rw-r--r-- | crates/hir_def/src/type_ref.rs | 245 |
1 files changed, 245 insertions, 0 deletions
diff --git a/crates/hir_def/src/type_ref.rs b/crates/hir_def/src/type_ref.rs new file mode 100644 index 000000000..1a78c1444 --- /dev/null +++ b/crates/hir_def/src/type_ref.rs | |||
@@ -0,0 +1,245 @@ | |||
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 | } | ||