diff options
Diffstat (limited to 'crates/ra_hir_def/src/type_ref.rs')
-rw-r--r-- | crates/ra_hir_def/src/type_ref.rs | 162 |
1 files changed, 162 insertions, 0 deletions
diff --git a/crates/ra_hir_def/src/type_ref.rs b/crates/ra_hir_def/src/type_ref.rs new file mode 100644 index 000000000..8af061116 --- /dev/null +++ b/crates/ra_hir_def/src/type_ref.rs | |||
@@ -0,0 +1,162 @@ | |||
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 | |||
4 | use ra_syntax::ast::{self, TypeAscriptionOwner, TypeBoundsOwner}; | ||
5 | |||
6 | use crate::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 | /// Compare ty::Ty | ||
39 | #[derive(Clone, PartialEq, Eq, Hash, Debug)] | ||
40 | pub enum TypeRef { | ||
41 | Never, | ||
42 | Placeholder, | ||
43 | Tuple(Vec<TypeRef>), | ||
44 | Path(Path), | ||
45 | RawPtr(Box<TypeRef>, Mutability), | ||
46 | Reference(Box<TypeRef>, Mutability), | ||
47 | Array(Box<TypeRef> /*, Expr*/), | ||
48 | Slice(Box<TypeRef>), | ||
49 | /// A fn pointer. Last element of the vector is the return type. | ||
50 | Fn(Vec<TypeRef>), | ||
51 | // For | ||
52 | ImplTrait(Vec<TypeBound>), | ||
53 | DynTrait(Vec<TypeBound>), | ||
54 | Error, | ||
55 | } | ||
56 | |||
57 | #[derive(Clone, PartialEq, Eq, Hash, Debug)] | ||
58 | pub enum TypeBound { | ||
59 | Path(Path), | ||
60 | // also for<> bounds | ||
61 | // also Lifetimes | ||
62 | Error, | ||
63 | } | ||
64 | |||
65 | impl TypeRef { | ||
66 | /// Converts an `ast::TypeRef` to a `hir::TypeRef`. | ||
67 | pub fn from_ast(node: ast::TypeRef) -> Self { | ||
68 | match node { | ||
69 | ast::TypeRef::ParenType(inner) => TypeRef::from_ast_opt(inner.type_ref()), | ||
70 | ast::TypeRef::TupleType(inner) => { | ||
71 | TypeRef::Tuple(inner.fields().map(TypeRef::from_ast).collect()) | ||
72 | } | ||
73 | ast::TypeRef::NeverType(..) => TypeRef::Never, | ||
74 | ast::TypeRef::PathType(inner) => { | ||
75 | // FIXME: Use `Path::from_src` | ||
76 | inner.path().and_then(Path::from_ast).map(TypeRef::Path).unwrap_or(TypeRef::Error) | ||
77 | } | ||
78 | ast::TypeRef::PointerType(inner) => { | ||
79 | let inner_ty = TypeRef::from_ast_opt(inner.type_ref()); | ||
80 | let mutability = Mutability::from_mutable(inner.is_mut()); | ||
81 | TypeRef::RawPtr(Box::new(inner_ty), mutability) | ||
82 | } | ||
83 | ast::TypeRef::ArrayType(inner) => { | ||
84 | TypeRef::Array(Box::new(TypeRef::from_ast_opt(inner.type_ref()))) | ||
85 | } | ||
86 | ast::TypeRef::SliceType(inner) => { | ||
87 | TypeRef::Slice(Box::new(TypeRef::from_ast_opt(inner.type_ref()))) | ||
88 | } | ||
89 | ast::TypeRef::ReferenceType(inner) => { | ||
90 | let inner_ty = TypeRef::from_ast_opt(inner.type_ref()); | ||
91 | let mutability = Mutability::from_mutable(inner.is_mut()); | ||
92 | TypeRef::Reference(Box::new(inner_ty), mutability) | ||
93 | } | ||
94 | ast::TypeRef::PlaceholderType(_inner) => TypeRef::Placeholder, | ||
95 | ast::TypeRef::FnPointerType(inner) => { | ||
96 | let ret_ty = TypeRef::from_ast_opt(inner.ret_type().and_then(|rt| rt.type_ref())); | ||
97 | let mut params = if let Some(pl) = inner.param_list() { | ||
98 | pl.params().map(|p| p.ascribed_type()).map(TypeRef::from_ast_opt).collect() | ||
99 | } else { | ||
100 | Vec::new() | ||
101 | }; | ||
102 | params.push(ret_ty); | ||
103 | TypeRef::Fn(params) | ||
104 | } | ||
105 | // for types are close enough for our purposes to the inner type for now... | ||
106 | ast::TypeRef::ForType(inner) => TypeRef::from_ast_opt(inner.type_ref()), | ||
107 | ast::TypeRef::ImplTraitType(inner) => { | ||
108 | TypeRef::ImplTrait(type_bounds_from_ast(inner.type_bound_list())) | ||
109 | } | ||
110 | ast::TypeRef::DynTraitType(inner) => { | ||
111 | TypeRef::DynTrait(type_bounds_from_ast(inner.type_bound_list())) | ||
112 | } | ||
113 | } | ||
114 | } | ||
115 | |||
116 | pub fn from_ast_opt(node: Option<ast::TypeRef>) -> Self { | ||
117 | if let Some(node) = node { | ||
118 | TypeRef::from_ast(node) | ||
119 | } else { | ||
120 | TypeRef::Error | ||
121 | } | ||
122 | } | ||
123 | |||
124 | pub fn unit() -> TypeRef { | ||
125 | TypeRef::Tuple(Vec::new()) | ||
126 | } | ||
127 | } | ||
128 | |||
129 | pub(crate) fn type_bounds_from_ast(type_bounds_opt: Option<ast::TypeBoundList>) -> Vec<TypeBound> { | ||
130 | if let Some(type_bounds) = type_bounds_opt { | ||
131 | type_bounds.bounds().map(TypeBound::from_ast).collect() | ||
132 | } else { | ||
133 | vec![] | ||
134 | } | ||
135 | } | ||
136 | |||
137 | impl TypeBound { | ||
138 | pub fn from_ast(node: ast::TypeBound) -> Self { | ||
139 | match node.kind() { | ||
140 | ast::TypeBoundKind::PathType(path_type) => { | ||
141 | let path = match path_type.path() { | ||
142 | Some(p) => p, | ||
143 | None => return TypeBound::Error, | ||
144 | }; | ||
145 | // FIXME: Use `Path::from_src` | ||
146 | let path = match Path::from_ast(path) { | ||
147 | Some(p) => p, | ||
148 | None => return TypeBound::Error, | ||
149 | }; | ||
150 | TypeBound::Path(path) | ||
151 | } | ||
152 | ast::TypeBoundKind::ForType(_) | ast::TypeBoundKind::Lifetime(_) => TypeBound::Error, | ||
153 | } | ||
154 | } | ||
155 | |||
156 | pub fn as_path(&self) -> Option<&Path> { | ||
157 | match self { | ||
158 | TypeBound::Path(p) => Some(p), | ||
159 | _ => None, | ||
160 | } | ||
161 | } | ||
162 | } | ||