diff options
Diffstat (limited to 'crates/ra_hir/src/ty/lower.rs')
-rw-r--r-- | crates/ra_hir/src/ty/lower.rs | 333 |
1 files changed, 333 insertions, 0 deletions
diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs new file mode 100644 index 000000000..63e13a30e --- /dev/null +++ b/crates/ra_hir/src/ty/lower.rs | |||
@@ -0,0 +1,333 @@ | |||
1 | //! Methods for lowering the HIR to types. There are two main cases here: | ||
2 | //! | ||
3 | //! - Lowering a type reference like `&usize` or `Option<foo::bar::Baz>` to a | ||
4 | //! type: The entry point for this is `Ty::from_hir`. | ||
5 | //! - Building the type for an item: This happens through the `type_for_def` query. | ||
6 | //! | ||
7 | //! This usually involves resolving names, collecting generic arguments etc. | ||
8 | |||
9 | use std::sync::Arc; | ||
10 | |||
11 | use crate::{ | ||
12 | Function, Struct, StructField, Enum, EnumVariant, Path, Name, | ||
13 | ModuleDef, | ||
14 | HirDatabase, | ||
15 | type_ref::TypeRef, | ||
16 | name::KnownName, | ||
17 | nameres::Namespace, | ||
18 | resolve::{Resolver, Resolution}, | ||
19 | path::{ PathSegment, GenericArg}, | ||
20 | generics::GenericParams, | ||
21 | adt::VariantDef, | ||
22 | }; | ||
23 | use super::{Ty, primitive, FnSig, Substs}; | ||
24 | |||
25 | impl Ty { | ||
26 | pub(crate) fn from_hir(db: &impl HirDatabase, resolver: &Resolver, type_ref: &TypeRef) -> Self { | ||
27 | match type_ref { | ||
28 | TypeRef::Never => Ty::Never, | ||
29 | TypeRef::Tuple(inner) => { | ||
30 | let inner_tys = | ||
31 | inner.iter().map(|tr| Ty::from_hir(db, resolver, tr)).collect::<Vec<_>>(); | ||
32 | Ty::Tuple(inner_tys.into()) | ||
33 | } | ||
34 | TypeRef::Path(path) => Ty::from_hir_path(db, resolver, path), | ||
35 | TypeRef::RawPtr(inner, mutability) => { | ||
36 | let inner_ty = Ty::from_hir(db, resolver, inner); | ||
37 | Ty::RawPtr(Arc::new(inner_ty), *mutability) | ||
38 | } | ||
39 | TypeRef::Array(inner) => { | ||
40 | let inner_ty = Ty::from_hir(db, resolver, inner); | ||
41 | Ty::Array(Arc::new(inner_ty)) | ||
42 | } | ||
43 | TypeRef::Slice(inner) => { | ||
44 | let inner_ty = Ty::from_hir(db, resolver, inner); | ||
45 | Ty::Slice(Arc::new(inner_ty)) | ||
46 | } | ||
47 | TypeRef::Reference(inner, mutability) => { | ||
48 | let inner_ty = Ty::from_hir(db, resolver, inner); | ||
49 | Ty::Ref(Arc::new(inner_ty), *mutability) | ||
50 | } | ||
51 | TypeRef::Placeholder => Ty::Unknown, | ||
52 | TypeRef::Fn(params) => { | ||
53 | let mut inner_tys = | ||
54 | params.iter().map(|tr| Ty::from_hir(db, resolver, tr)).collect::<Vec<_>>(); | ||
55 | let return_ty = | ||
56 | inner_tys.pop().expect("TypeRef::Fn should always have at least return type"); | ||
57 | let sig = FnSig { input: inner_tys, output: return_ty }; | ||
58 | Ty::FnPtr(Arc::new(sig)) | ||
59 | } | ||
60 | TypeRef::Error => Ty::Unknown, | ||
61 | } | ||
62 | } | ||
63 | |||
64 | pub(crate) fn from_hir_path(db: &impl HirDatabase, resolver: &Resolver, path: &Path) -> Self { | ||
65 | if let Some(name) = path.as_ident() { | ||
66 | // TODO handle primitive type names in resolver as well? | ||
67 | if let Some(int_ty) = primitive::UncertainIntTy::from_name(name) { | ||
68 | return Ty::Int(int_ty); | ||
69 | } else if let Some(float_ty) = primitive::UncertainFloatTy::from_name(name) { | ||
70 | return Ty::Float(float_ty); | ||
71 | } else if let Some(known) = name.as_known_name() { | ||
72 | match known { | ||
73 | KnownName::Bool => return Ty::Bool, | ||
74 | KnownName::Char => return Ty::Char, | ||
75 | KnownName::Str => return Ty::Str, | ||
76 | _ => {} | ||
77 | } | ||
78 | } | ||
79 | } | ||
80 | |||
81 | // Resolve the path (in type namespace) | ||
82 | let resolution = resolver.resolve_path(db, path).take_types(); | ||
83 | |||
84 | let def = match resolution { | ||
85 | Some(Resolution::Def(def)) => def, | ||
86 | Some(Resolution::LocalBinding(..)) => { | ||
87 | // this should never happen | ||
88 | panic!("path resolved to local binding in type ns"); | ||
89 | } | ||
90 | Some(Resolution::GenericParam(idx)) => { | ||
91 | return Ty::Param { | ||
92 | idx, | ||
93 | // TODO: maybe return name in resolution? | ||
94 | name: path | ||
95 | .as_ident() | ||
96 | .expect("generic param should be single-segment path") | ||
97 | .clone(), | ||
98 | }; | ||
99 | } | ||
100 | Some(Resolution::SelfType(impl_block)) => { | ||
101 | return impl_block.target_ty(db); | ||
102 | } | ||
103 | None => return Ty::Unknown, | ||
104 | }; | ||
105 | |||
106 | let typable: TypableDef = match def.into() { | ||
107 | None => return Ty::Unknown, | ||
108 | Some(it) => it, | ||
109 | }; | ||
110 | let ty = db.type_for_def(typable, Namespace::Types); | ||
111 | let substs = Ty::substs_from_path(db, resolver, path, typable); | ||
112 | ty.apply_substs(substs) | ||
113 | } | ||
114 | |||
115 | pub(super) fn substs_from_path_segment( | ||
116 | db: &impl HirDatabase, | ||
117 | resolver: &Resolver, | ||
118 | segment: &PathSegment, | ||
119 | resolved: TypableDef, | ||
120 | ) -> Substs { | ||
121 | let mut substs = Vec::new(); | ||
122 | let def_generics = match resolved { | ||
123 | TypableDef::Function(func) => func.generic_params(db), | ||
124 | TypableDef::Struct(s) => s.generic_params(db), | ||
125 | TypableDef::Enum(e) => e.generic_params(db), | ||
126 | TypableDef::EnumVariant(var) => var.parent_enum(db).generic_params(db), | ||
127 | }; | ||
128 | let parent_param_count = def_generics.count_parent_params(); | ||
129 | substs.extend((0..parent_param_count).map(|_| Ty::Unknown)); | ||
130 | if let Some(generic_args) = &segment.args_and_bindings { | ||
131 | // if args are provided, it should be all of them, but we can't rely on that | ||
132 | let param_count = def_generics.params.len(); | ||
133 | for arg in generic_args.args.iter().take(param_count) { | ||
134 | match arg { | ||
135 | GenericArg::Type(type_ref) => { | ||
136 | let ty = Ty::from_hir(db, resolver, type_ref); | ||
137 | substs.push(ty); | ||
138 | } | ||
139 | } | ||
140 | } | ||
141 | } | ||
142 | // add placeholders for args that were not provided | ||
143 | // TODO: handle defaults | ||
144 | let supplied_params = substs.len(); | ||
145 | for _ in supplied_params..def_generics.count_params_including_parent() { | ||
146 | substs.push(Ty::Unknown); | ||
147 | } | ||
148 | assert_eq!(substs.len(), def_generics.count_params_including_parent()); | ||
149 | Substs(substs.into()) | ||
150 | } | ||
151 | |||
152 | /// Collect generic arguments from a path into a `Substs`. See also | ||
153 | /// `create_substs_for_ast_path` and `def_to_ty` in rustc. | ||
154 | pub(super) fn substs_from_path( | ||
155 | db: &impl HirDatabase, | ||
156 | resolver: &Resolver, | ||
157 | path: &Path, | ||
158 | resolved: TypableDef, | ||
159 | ) -> Substs { | ||
160 | let last = path.segments.last().expect("path should have at least one segment"); | ||
161 | let segment = match resolved { | ||
162 | TypableDef::Function(_) => last, | ||
163 | TypableDef::Struct(_) => last, | ||
164 | TypableDef::Enum(_) => last, | ||
165 | TypableDef::EnumVariant(_) => { | ||
166 | // the generic args for an enum variant may be either specified | ||
167 | // on the segment referring to the enum, or on the segment | ||
168 | // referring to the variant. So `Option::<T>::None` and | ||
169 | // `Option::None::<T>` are both allowed (though the former is | ||
170 | // preferred). See also `def_ids_for_path_segments` in rustc. | ||
171 | let len = path.segments.len(); | ||
172 | let segment = if len >= 2 && path.segments[len - 2].args_and_bindings.is_some() { | ||
173 | // Option::<T>::None | ||
174 | &path.segments[len - 2] | ||
175 | } else { | ||
176 | // Option::None::<T> | ||
177 | last | ||
178 | }; | ||
179 | segment | ||
180 | } | ||
181 | }; | ||
182 | Ty::substs_from_path_segment(db, resolver, segment, resolved) | ||
183 | } | ||
184 | } | ||
185 | |||
186 | /// Build the declared type of an item. This depends on the namespace; e.g. for | ||
187 | /// `struct Foo(usize)`, we have two types: The type of the struct itself, and | ||
188 | /// the constructor function `(usize) -> Foo` which lives in the values | ||
189 | /// namespace. | ||
190 | pub(crate) fn type_for_def(db: &impl HirDatabase, def: TypableDef, ns: Namespace) -> Ty { | ||
191 | match (def, ns) { | ||
192 | (TypableDef::Function(f), Namespace::Values) => type_for_fn(db, f), | ||
193 | (TypableDef::Struct(s), Namespace::Types) => type_for_struct(db, s), | ||
194 | (TypableDef::Struct(s), Namespace::Values) => type_for_struct_constructor(db, s), | ||
195 | (TypableDef::Enum(e), Namespace::Types) => type_for_enum(db, e), | ||
196 | (TypableDef::EnumVariant(v), Namespace::Values) => type_for_enum_variant_constructor(db, v), | ||
197 | |||
198 | // 'error' cases: | ||
199 | (TypableDef::Function(_), Namespace::Types) => Ty::Unknown, | ||
200 | (TypableDef::Enum(_), Namespace::Values) => Ty::Unknown, | ||
201 | (TypableDef::EnumVariant(_), Namespace::Types) => Ty::Unknown, | ||
202 | } | ||
203 | } | ||
204 | |||
205 | /// Build the type of a specific field of a struct or enum variant. | ||
206 | pub(crate) fn type_for_field(db: &impl HirDatabase, field: StructField) -> Ty { | ||
207 | let parent_def = field.parent_def(db); | ||
208 | let resolver = match parent_def { | ||
209 | VariantDef::Struct(it) => it.resolver(db), | ||
210 | VariantDef::EnumVariant(it) => it.parent_enum(db).resolver(db), | ||
211 | }; | ||
212 | let var_data = parent_def.variant_data(db); | ||
213 | let type_ref = &var_data.fields().unwrap()[field.id].type_ref; | ||
214 | Ty::from_hir(db, &resolver, type_ref) | ||
215 | } | ||
216 | |||
217 | /// Build the declared type of a function. This should not need to look at the | ||
218 | /// function body. | ||
219 | fn type_for_fn(db: &impl HirDatabase, def: Function) -> Ty { | ||
220 | let signature = def.signature(db); | ||
221 | let resolver = def.resolver(db); | ||
222 | let generics = def.generic_params(db); | ||
223 | let name = def.name(db); | ||
224 | let input = | ||
225 | signature.params().iter().map(|tr| Ty::from_hir(db, &resolver, tr)).collect::<Vec<_>>(); | ||
226 | let output = Ty::from_hir(db, &resolver, signature.ret_type()); | ||
227 | let sig = Arc::new(FnSig { input, output }); | ||
228 | let substs = make_substs(&generics); | ||
229 | Ty::FnDef { def: def.into(), sig, name, substs } | ||
230 | } | ||
231 | |||
232 | /// Build the type of a tuple struct constructor. | ||
233 | fn type_for_struct_constructor(db: &impl HirDatabase, def: Struct) -> Ty { | ||
234 | let var_data = def.variant_data(db); | ||
235 | let fields = match var_data.fields() { | ||
236 | Some(fields) => fields, | ||
237 | None => return type_for_struct(db, def), // Unit struct | ||
238 | }; | ||
239 | let resolver = def.resolver(db); | ||
240 | let generics = def.generic_params(db); | ||
241 | let name = def.name(db).unwrap_or_else(Name::missing); | ||
242 | let input = fields | ||
243 | .iter() | ||
244 | .map(|(_, field)| Ty::from_hir(db, &resolver, &field.type_ref)) | ||
245 | .collect::<Vec<_>>(); | ||
246 | let output = type_for_struct(db, def); | ||
247 | let sig = Arc::new(FnSig { input, output }); | ||
248 | let substs = make_substs(&generics); | ||
249 | Ty::FnDef { def: def.into(), sig, name, substs } | ||
250 | } | ||
251 | |||
252 | /// Build the type of a tuple enum variant constructor. | ||
253 | fn type_for_enum_variant_constructor(db: &impl HirDatabase, def: EnumVariant) -> Ty { | ||
254 | let var_data = def.variant_data(db); | ||
255 | let fields = match var_data.fields() { | ||
256 | Some(fields) => fields, | ||
257 | None => return type_for_enum(db, def.parent_enum(db)), // Unit variant | ||
258 | }; | ||
259 | let resolver = def.parent_enum(db).resolver(db); | ||
260 | let generics = def.parent_enum(db).generic_params(db); | ||
261 | let name = def.name(db).unwrap_or_else(Name::missing); | ||
262 | let input = fields | ||
263 | .iter() | ||
264 | .map(|(_, field)| Ty::from_hir(db, &resolver, &field.type_ref)) | ||
265 | .collect::<Vec<_>>(); | ||
266 | let substs = make_substs(&generics); | ||
267 | let output = type_for_enum(db, def.parent_enum(db)).apply_substs(substs.clone()); | ||
268 | let sig = Arc::new(FnSig { input, output }); | ||
269 | Ty::FnDef { def: def.into(), sig, name, substs } | ||
270 | } | ||
271 | |||
272 | fn make_substs(generics: &GenericParams) -> Substs { | ||
273 | Substs( | ||
274 | generics | ||
275 | .params_including_parent() | ||
276 | .into_iter() | ||
277 | .map(|p| Ty::Param { idx: p.idx, name: p.name.clone() }) | ||
278 | .collect::<Vec<_>>() | ||
279 | .into(), | ||
280 | ) | ||
281 | } | ||
282 | |||
283 | fn type_for_struct(db: &impl HirDatabase, s: Struct) -> Ty { | ||
284 | let generics = s.generic_params(db); | ||
285 | Ty::Adt { | ||
286 | def_id: s.into(), | ||
287 | name: s.name(db).unwrap_or_else(Name::missing), | ||
288 | substs: make_substs(&generics), | ||
289 | } | ||
290 | } | ||
291 | |||
292 | fn type_for_enum(db: &impl HirDatabase, s: Enum) -> Ty { | ||
293 | let generics = s.generic_params(db); | ||
294 | Ty::Adt { | ||
295 | def_id: s.into(), | ||
296 | name: s.name(db).unwrap_or_else(Name::missing), | ||
297 | substs: make_substs(&generics), | ||
298 | } | ||
299 | } | ||
300 | |||
301 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] | ||
302 | pub enum TypableDef { | ||
303 | Function(Function), | ||
304 | Struct(Struct), | ||
305 | Enum(Enum), | ||
306 | EnumVariant(EnumVariant), | ||
307 | } | ||
308 | impl_froms!(TypableDef: Function, Struct, Enum, EnumVariant); | ||
309 | |||
310 | impl From<ModuleDef> for Option<TypableDef> { | ||
311 | fn from(def: ModuleDef) -> Option<TypableDef> { | ||
312 | let res = match def { | ||
313 | ModuleDef::Function(f) => f.into(), | ||
314 | ModuleDef::Struct(s) => s.into(), | ||
315 | ModuleDef::Enum(e) => e.into(), | ||
316 | ModuleDef::EnumVariant(v) => v.into(), | ||
317 | ModuleDef::Const(_) | ||
318 | | ModuleDef::Static(_) | ||
319 | | ModuleDef::Module(_) | ||
320 | | ModuleDef::Trait(_) | ||
321 | | ModuleDef::Type(_) => return None, | ||
322 | }; | ||
323 | Some(res) | ||
324 | } | ||
325 | } | ||
326 | |||
327 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] | ||
328 | pub enum CallableDef { | ||
329 | Function(Function), | ||
330 | Struct(Struct), | ||
331 | EnumVariant(EnumVariant), | ||
332 | } | ||
333 | impl_froms!(CallableDef: Function, Struct, EnumVariant); | ||