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