diff options
Diffstat (limited to 'crates/ra_hir/src/ty/lower.rs')
-rw-r--r-- | crates/ra_hir/src/ty/lower.rs | 318 |
1 files changed, 318 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..cc9e0fd40 --- /dev/null +++ b/crates/ra_hir/src/ty/lower.rs | |||
@@ -0,0 +1,318 @@ | |||
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::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 | /// Collect generic arguments from a path into a `Substs`. See also | ||
116 | /// `create_substs_for_ast_path` and `def_to_ty` in rustc. | ||
117 | pub(super) fn substs_from_path( | ||
118 | db: &impl HirDatabase, | ||
119 | resolver: &Resolver, | ||
120 | path: &Path, | ||
121 | resolved: TypableDef, | ||
122 | ) -> Substs { | ||
123 | let mut substs = Vec::new(); | ||
124 | let last = path.segments.last().expect("path should have at least one segment"); | ||
125 | let (def_generics, segment) = match resolved { | ||
126 | TypableDef::Function(func) => (func.generic_params(db), last), | ||
127 | TypableDef::Struct(s) => (s.generic_params(db), last), | ||
128 | TypableDef::Enum(e) => (e.generic_params(db), last), | ||
129 | TypableDef::EnumVariant(var) => { | ||
130 | // the generic args for an enum variant may be either specified | ||
131 | // on the segment referring to the enum, or on the segment | ||
132 | // referring to the variant. So `Option::<T>::None` and | ||
133 | // `Option::None::<T>` are both allowed (though the former is | ||
134 | // preferred). See also `def_ids_for_path_segments` in rustc. | ||
135 | let len = path.segments.len(); | ||
136 | let segment = if len >= 2 && path.segments[len - 2].args_and_bindings.is_some() { | ||
137 | // Option::<T>::None | ||
138 | &path.segments[len - 2] | ||
139 | } else { | ||
140 | // Option::None::<T> | ||
141 | last | ||
142 | }; | ||
143 | (var.parent_enum(db).generic_params(db), segment) | ||
144 | } | ||
145 | }; | ||
146 | let parent_param_count = def_generics.count_parent_params(); | ||
147 | substs.extend((0..parent_param_count).map(|_| Ty::Unknown)); | ||
148 | if let Some(generic_args) = &segment.args_and_bindings { | ||
149 | // if args are provided, it should be all of them, but we can't rely on that | ||
150 | let param_count = def_generics.params.len(); | ||
151 | for arg in generic_args.args.iter().take(param_count) { | ||
152 | match arg { | ||
153 | GenericArg::Type(type_ref) => { | ||
154 | let ty = Ty::from_hir(db, resolver, type_ref); | ||
155 | substs.push(ty); | ||
156 | } | ||
157 | } | ||
158 | } | ||
159 | } | ||
160 | // add placeholders for args that were not provided | ||
161 | // TODO: handle defaults | ||
162 | let supplied_params = substs.len(); | ||
163 | for _ in supplied_params..def_generics.count_params_including_parent() { | ||
164 | substs.push(Ty::Unknown); | ||
165 | } | ||
166 | assert_eq!(substs.len(), def_generics.count_params_including_parent()); | ||
167 | Substs(substs.into()) | ||
168 | } | ||
169 | } | ||
170 | |||
171 | /// Build the declared type of an item. This depends on the namespace; e.g. for | ||
172 | /// `struct Foo(usize)`, we have two types: The type of the struct itself, and | ||
173 | /// the constructor function `(usize) -> Foo` which lives in the values | ||
174 | /// namespace. | ||
175 | pub(crate) fn type_for_def(db: &impl HirDatabase, def: TypableDef, ns: Namespace) -> Ty { | ||
176 | match (def, ns) { | ||
177 | (TypableDef::Function(f), Namespace::Values) => type_for_fn(db, f), | ||
178 | (TypableDef::Struct(s), Namespace::Types) => type_for_struct(db, s), | ||
179 | (TypableDef::Struct(s), Namespace::Values) => type_for_struct_constructor(db, s), | ||
180 | (TypableDef::Enum(e), Namespace::Types) => type_for_enum(db, e), | ||
181 | (TypableDef::EnumVariant(v), Namespace::Values) => type_for_enum_variant_constructor(db, v), | ||
182 | |||
183 | // 'error' cases: | ||
184 | (TypableDef::Function(_), Namespace::Types) => Ty::Unknown, | ||
185 | (TypableDef::Enum(_), Namespace::Values) => Ty::Unknown, | ||
186 | (TypableDef::EnumVariant(_), Namespace::Types) => Ty::Unknown, | ||
187 | } | ||
188 | } | ||
189 | |||
190 | /// Build the type of a specific field of a struct or enum variant. | ||
191 | pub(crate) fn type_for_field(db: &impl HirDatabase, field: StructField) -> Ty { | ||
192 | let parent_def = field.parent_def(db); | ||
193 | let resolver = match parent_def { | ||
194 | VariantDef::Struct(it) => it.resolver(db), | ||
195 | VariantDef::EnumVariant(it) => it.parent_enum(db).resolver(db), | ||
196 | }; | ||
197 | let var_data = parent_def.variant_data(db); | ||
198 | let type_ref = &var_data.fields().unwrap()[field.id].type_ref; | ||
199 | Ty::from_hir(db, &resolver, type_ref) | ||
200 | } | ||
201 | |||
202 | /// Build the declared type of a function. This should not need to look at the | ||
203 | /// function body. | ||
204 | fn type_for_fn(db: &impl HirDatabase, def: Function) -> Ty { | ||
205 | let signature = def.signature(db); | ||
206 | let resolver = def.resolver(db); | ||
207 | let generics = def.generic_params(db); | ||
208 | let name = def.name(db); | ||
209 | let input = | ||
210 | signature.params().iter().map(|tr| Ty::from_hir(db, &resolver, tr)).collect::<Vec<_>>(); | ||
211 | let output = Ty::from_hir(db, &resolver, signature.ret_type()); | ||
212 | let sig = Arc::new(FnSig { input, output }); | ||
213 | let substs = make_substs(&generics); | ||
214 | Ty::FnDef { def: def.into(), sig, name, substs } | ||
215 | } | ||
216 | |||
217 | /// Build the type of a tuple struct constructor. | ||
218 | fn type_for_struct_constructor(db: &impl HirDatabase, def: Struct) -> Ty { | ||
219 | let var_data = def.variant_data(db); | ||
220 | let fields = match var_data.fields() { | ||
221 | Some(fields) => fields, | ||
222 | None => return type_for_struct(db, def), // Unit struct | ||
223 | }; | ||
224 | let resolver = def.resolver(db); | ||
225 | let generics = def.generic_params(db); | ||
226 | let name = def.name(db).unwrap_or_else(Name::missing); | ||
227 | let input = fields | ||
228 | .iter() | ||
229 | .map(|(_, field)| Ty::from_hir(db, &resolver, &field.type_ref)) | ||
230 | .collect::<Vec<_>>(); | ||
231 | let output = type_for_struct(db, def); | ||
232 | let sig = Arc::new(FnSig { input, output }); | ||
233 | let substs = make_substs(&generics); | ||
234 | Ty::FnDef { def: def.into(), sig, name, substs } | ||
235 | } | ||
236 | |||
237 | /// Build the type of a tuple enum variant constructor. | ||
238 | fn type_for_enum_variant_constructor(db: &impl HirDatabase, def: EnumVariant) -> Ty { | ||
239 | let var_data = def.variant_data(db); | ||
240 | let fields = match var_data.fields() { | ||
241 | Some(fields) => fields, | ||
242 | None => return type_for_enum(db, def.parent_enum(db)), // Unit variant | ||
243 | }; | ||
244 | let resolver = def.parent_enum(db).resolver(db); | ||
245 | let generics = def.parent_enum(db).generic_params(db); | ||
246 | let name = def.name(db).unwrap_or_else(Name::missing); | ||
247 | let input = fields | ||
248 | .iter() | ||
249 | .map(|(_, field)| Ty::from_hir(db, &resolver, &field.type_ref)) | ||
250 | .collect::<Vec<_>>(); | ||
251 | let substs = make_substs(&generics); | ||
252 | let output = type_for_enum(db, def.parent_enum(db)).apply_substs(substs.clone()); | ||
253 | let sig = Arc::new(FnSig { input, output }); | ||
254 | Ty::FnDef { def: def.into(), sig, name, substs } | ||
255 | } | ||
256 | |||
257 | fn make_substs(generics: &GenericParams) -> Substs { | ||
258 | Substs( | ||
259 | generics | ||
260 | .params_including_parent() | ||
261 | .into_iter() | ||
262 | .map(|p| Ty::Param { idx: p.idx, name: p.name.clone() }) | ||
263 | .collect::<Vec<_>>() | ||
264 | .into(), | ||
265 | ) | ||
266 | } | ||
267 | |||
268 | fn type_for_struct(db: &impl HirDatabase, s: Struct) -> Ty { | ||
269 | let generics = s.generic_params(db); | ||
270 | Ty::Adt { | ||
271 | def_id: s.into(), | ||
272 | name: s.name(db).unwrap_or_else(Name::missing), | ||
273 | substs: make_substs(&generics), | ||
274 | } | ||
275 | } | ||
276 | |||
277 | fn type_for_enum(db: &impl HirDatabase, s: Enum) -> Ty { | ||
278 | let generics = s.generic_params(db); | ||
279 | Ty::Adt { | ||
280 | def_id: s.into(), | ||
281 | name: s.name(db).unwrap_or_else(Name::missing), | ||
282 | substs: make_substs(&generics), | ||
283 | } | ||
284 | } | ||
285 | |||
286 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] | ||
287 | pub enum TypableDef { | ||
288 | Function(Function), | ||
289 | Struct(Struct), | ||
290 | Enum(Enum), | ||
291 | EnumVariant(EnumVariant), | ||
292 | } | ||
293 | impl_froms!(TypableDef: Function, Struct, Enum, EnumVariant); | ||
294 | |||
295 | impl From<ModuleDef> for Option<TypableDef> { | ||
296 | fn from(def: ModuleDef) -> Option<TypableDef> { | ||
297 | let res = match def { | ||
298 | ModuleDef::Function(f) => f.into(), | ||
299 | ModuleDef::Struct(s) => s.into(), | ||
300 | ModuleDef::Enum(e) => e.into(), | ||
301 | ModuleDef::EnumVariant(v) => v.into(), | ||
302 | ModuleDef::Const(_) | ||
303 | | ModuleDef::Static(_) | ||
304 | | ModuleDef::Module(_) | ||
305 | | ModuleDef::Trait(_) | ||
306 | | ModuleDef::Type(_) => return None, | ||
307 | }; | ||
308 | Some(res) | ||
309 | } | ||
310 | } | ||
311 | |||
312 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] | ||
313 | pub enum CallableDef { | ||
314 | Function(Function), | ||
315 | Struct(Struct), | ||
316 | EnumVariant(EnumVariant), | ||
317 | } | ||
318 | impl_froms!(CallableDef: Function, Struct, EnumVariant); | ||