aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_def/src/type_ref.rs
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2020-08-13 15:28:27 +0100
committerAleksey Kladov <[email protected]>2020-08-13 15:29:33 +0100
commitb28c54a2c239acd73f2eea80fda9ee3960d2c046 (patch)
tree1bf0ea193bdb3b16ff42c2c01118b13a4276b2bb /crates/hir_def/src/type_ref.rs
parentb7aa4898e0841ab8199643f89a0caa967b698ca8 (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.rs245
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.
3use syntax::ast::{self};
4
5use crate::{body::LowerCtx, path::Path};
6
7#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
8pub enum Mutability {
9 Shared,
10 Mut,
11}
12
13impl 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)]
38pub enum Rawness {
39 RawPtr,
40 Ref,
41}
42
43impl 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)]
55pub 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)]
73pub enum TypeBound {
74 Path(Path),
75 // also for<> bounds
76 // also Lifetimes
77 Error,
78}
79
80impl 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
209pub(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
220impl 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}