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.rs318
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
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::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 /// 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.
175pub(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.
191pub(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.
204fn 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.
218fn 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.
238fn 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
257fn 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
268fn 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
277fn 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)]
287pub enum TypableDef {
288 Function(Function),
289 Struct(Struct),
290 Enum(Enum),
291 EnumVariant(EnumVariant),
292}
293impl_froms!(TypableDef: Function, Struct, Enum, EnumVariant);
294
295impl 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)]
313pub enum CallableDef {
314 Function(Function),
315 Struct(Struct),
316 EnumVariant(EnumVariant),
317}
318impl_froms!(CallableDef: Function, Struct, EnumVariant);