aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/ty/lower.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir/src/ty/lower.rs')
-rw-r--r--crates/ra_hir/src/ty/lower.rs333
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
9use std::sync::Arc;
10
11use 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};
23use super::{Ty, primitive, FnSig, Substs};
24
25impl 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.
190pub(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.
206pub(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.
219fn 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.
233fn 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.
253fn 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
272fn 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
283fn 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
292fn 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)]
302pub enum TypableDef {
303 Function(Function),
304 Struct(Struct),
305 Enum(Enum),
306 EnumVariant(EnumVariant),
307}
308impl_froms!(TypableDef: Function, Struct, Enum, EnumVariant);
309
310impl 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)]
328pub enum CallableDef {
329 Function(Function),
330 Struct(Struct),
331 EnumVariant(EnumVariant),
332}
333impl_froms!(CallableDef: Function, Struct, EnumVariant);