diff options
Diffstat (limited to 'crates/hir/src/lib.rs')
-rw-r--r-- | crates/hir/src/lib.rs | 2142 |
1 files changed, 2114 insertions, 28 deletions
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 69fcdab07..a38e20300 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs | |||
@@ -20,49 +20,2135 @@ | |||
20 | #![recursion_limit = "512"] | 20 | #![recursion_limit = "512"] |
21 | 21 | ||
22 | mod semantics; | 22 | mod semantics; |
23 | pub mod db; | ||
24 | mod source_analyzer; | 23 | mod source_analyzer; |
25 | 24 | ||
26 | pub mod diagnostics; | ||
27 | |||
28 | mod from_id; | 25 | mod from_id; |
29 | mod code_model; | ||
30 | mod attrs; | 26 | mod attrs; |
31 | mod has_source; | 27 | mod has_source; |
32 | 28 | ||
29 | pub mod diagnostics; | ||
30 | pub mod db; | ||
31 | |||
32 | use std::{iter, sync::Arc}; | ||
33 | |||
34 | use arrayvec::ArrayVec; | ||
35 | use base_db::{CrateDisplayName, CrateId, Edition, FileId}; | ||
36 | use either::Either; | ||
37 | use hir_def::{ | ||
38 | adt::{ReprKind, VariantData}, | ||
39 | expr::{BindingAnnotation, LabelId, Pat, PatId}, | ||
40 | item_tree::ItemTreeNode, | ||
41 | lang_item::LangItemTarget, | ||
42 | per_ns::PerNs, | ||
43 | resolver::{HasResolver, Resolver}, | ||
44 | src::HasSource as _, | ||
45 | AdtId, AssocContainerId, AssocItemId, AssocItemLoc, AttrDefId, ConstId, ConstParamId, | ||
46 | DefWithBodyId, EnumId, FunctionId, GenericDefId, HasModule, ImplId, LifetimeParamId, | ||
47 | LocalEnumVariantId, LocalFieldId, Lookup, ModuleId, StaticId, StructId, TraitId, TypeAliasId, | ||
48 | TypeParamId, UnionId, | ||
49 | }; | ||
50 | use hir_expand::{diagnostics::DiagnosticSink, name::name, MacroDefKind}; | ||
51 | use hir_ty::{ | ||
52 | autoderef, | ||
53 | display::{write_bounds_like_dyn_trait_with_prefix, HirDisplayError, HirFormatter}, | ||
54 | method_resolution, | ||
55 | traits::{FnTrait, Solution, SolutionVariables}, | ||
56 | AliasTy, BoundVar, CallableDefId, CallableSig, Canonical, DebruijnIndex, GenericPredicate, | ||
57 | InEnvironment, Obligation, ProjectionPredicate, ProjectionTy, Scalar, Substs, TraitEnvironment, | ||
58 | Ty, TyDefId, TyVariableKind, | ||
59 | }; | ||
60 | use rustc_hash::FxHashSet; | ||
61 | use stdx::{format_to, impl_from}; | ||
62 | use syntax::{ | ||
63 | ast::{self, AttrsOwner, NameOwner}, | ||
64 | AstNode, SmolStr, | ||
65 | }; | ||
66 | use tt::{Ident, Leaf, Literal, TokenTree}; | ||
67 | |||
68 | use crate::db::{DefDatabase, HirDatabase}; | ||
69 | |||
33 | pub use crate::{ | 70 | pub use crate::{ |
34 | attrs::{HasAttrs, Namespace}, | 71 | attrs::{HasAttrs, Namespace}, |
35 | code_model::{ | ||
36 | Access, Adt, AsAssocItem, AssocItem, AssocItemContainer, BuiltinType, Callable, | ||
37 | CallableKind, Const, ConstParam, Crate, CrateDependency, DefWithBody, Enum, Field, | ||
38 | FieldSource, Function, GenericDef, GenericParam, HasVisibility, Impl, Label, LifetimeParam, | ||
39 | Local, MacroDef, Module, ModuleDef, ScopeDef, Static, Struct, Trait, Type, TypeAlias, | ||
40 | TypeParam, Union, Variant, VariantDef, | ||
41 | }, | ||
42 | has_source::HasSource, | 72 | has_source::HasSource, |
43 | semantics::{PathResolution, Semantics, SemanticsScope}, | 73 | semantics::{PathResolution, Semantics, SemanticsScope}, |
44 | }; | 74 | }; |
45 | 75 | ||
46 | pub use hir_def::{ | 76 | // Be careful with these re-exports. |
47 | adt::StructKind, | 77 | // |
48 | attr::{Attrs, Documentation}, | 78 | // `hir` is the boundary between the compiler and the IDE. It should try hard to |
49 | body::scope::ExprScopes, | 79 | // isolate the compiler from the ide, to allow the two to be refactored |
50 | find_path::PrefixKind, | 80 | // independently. Re-exporting something from the compiler is the sure way to |
51 | import_map, | 81 | // breach the boundary. |
52 | item_scope::ItemInNs, | 82 | // |
53 | nameres::ModuleSource, | 83 | // Generally, a refactoring which *removes* a name from this list is a good |
54 | path::{ModPath, PathKind}, | 84 | // idea! |
55 | type_ref::{Mutability, TypeRef}, | 85 | pub use { |
56 | visibility::Visibility, | 86 | hir_def::{ |
57 | }; | 87 | adt::StructKind, |
58 | pub use hir_expand::{ | 88 | attr::{Attrs, Documentation}, |
59 | name::{known, AsName, Name}, | 89 | body::scope::ExprScopes, |
60 | ExpandResult, HirFileId, InFile, MacroCallId, MacroCallLoc, /* FIXME */ MacroDefId, | 90 | find_path::PrefixKind, |
61 | MacroFile, Origin, | 91 | import_map, |
92 | item_scope::ItemInNs, | ||
93 | nameres::ModuleSource, | ||
94 | path::{ModPath, PathKind}, | ||
95 | type_ref::{Mutability, TypeRef}, | ||
96 | visibility::Visibility, | ||
97 | }, | ||
98 | hir_expand::{ | ||
99 | name::{known, AsName, Name}, | ||
100 | ExpandResult, HirFileId, InFile, MacroCallId, MacroCallLoc, /* FIXME */ MacroDefId, | ||
101 | MacroFile, Origin, | ||
102 | }, | ||
103 | hir_ty::display::HirDisplay, | ||
62 | }; | 104 | }; |
63 | pub use hir_ty::display::HirDisplay; | ||
64 | 105 | ||
65 | // These are negative re-exports: pub using these names is forbidden, they | 106 | // These are negative re-exports: pub using these names is forbidden, they |
66 | // should remain private to hir internals. | 107 | // should remain private to hir internals. |
67 | #[allow(unused)] | 108 | #[allow(unused)] |
68 | use {hir_def::path::Path, hir_expand::hygiene::Hygiene}; | 109 | use {hir_def::path::Path, hir_expand::hygiene::Hygiene}; |
110 | |||
111 | /// hir::Crate describes a single crate. It's the main interface with which | ||
112 | /// a crate's dependencies interact. Mostly, it should be just a proxy for the | ||
113 | /// root module. | ||
114 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
115 | pub struct Crate { | ||
116 | pub(crate) id: CrateId, | ||
117 | } | ||
118 | |||
119 | #[derive(Debug)] | ||
120 | pub struct CrateDependency { | ||
121 | pub krate: Crate, | ||
122 | pub name: Name, | ||
123 | } | ||
124 | |||
125 | impl Crate { | ||
126 | pub fn dependencies(self, db: &dyn HirDatabase) -> Vec<CrateDependency> { | ||
127 | db.crate_graph()[self.id] | ||
128 | .dependencies | ||
129 | .iter() | ||
130 | .map(|dep| { | ||
131 | let krate = Crate { id: dep.crate_id }; | ||
132 | let name = dep.as_name(); | ||
133 | CrateDependency { krate, name } | ||
134 | }) | ||
135 | .collect() | ||
136 | } | ||
137 | |||
138 | // FIXME: add `transitive_reverse_dependencies`. | ||
139 | pub fn reverse_dependencies(self, db: &dyn HirDatabase) -> Vec<Crate> { | ||
140 | let crate_graph = db.crate_graph(); | ||
141 | crate_graph | ||
142 | .iter() | ||
143 | .filter(|&krate| { | ||
144 | crate_graph[krate].dependencies.iter().any(|it| it.crate_id == self.id) | ||
145 | }) | ||
146 | .map(|id| Crate { id }) | ||
147 | .collect() | ||
148 | } | ||
149 | |||
150 | pub fn root_module(self, db: &dyn HirDatabase) -> Module { | ||
151 | let def_map = db.crate_def_map(self.id); | ||
152 | Module { id: def_map.module_id(def_map.root()) } | ||
153 | } | ||
154 | |||
155 | pub fn root_file(self, db: &dyn HirDatabase) -> FileId { | ||
156 | db.crate_graph()[self.id].root_file_id | ||
157 | } | ||
158 | |||
159 | pub fn edition(self, db: &dyn HirDatabase) -> Edition { | ||
160 | db.crate_graph()[self.id].edition | ||
161 | } | ||
162 | |||
163 | pub fn display_name(self, db: &dyn HirDatabase) -> Option<CrateDisplayName> { | ||
164 | db.crate_graph()[self.id].display_name.clone() | ||
165 | } | ||
166 | |||
167 | pub fn query_external_importables( | ||
168 | self, | ||
169 | db: &dyn DefDatabase, | ||
170 | query: import_map::Query, | ||
171 | ) -> impl Iterator<Item = Either<ModuleDef, MacroDef>> { | ||
172 | import_map::search_dependencies(db, self.into(), query).into_iter().map(|item| match item { | ||
173 | ItemInNs::Types(mod_id) | ItemInNs::Values(mod_id) => Either::Left(mod_id.into()), | ||
174 | ItemInNs::Macros(mac_id) => Either::Right(mac_id.into()), | ||
175 | }) | ||
176 | } | ||
177 | |||
178 | pub fn all(db: &dyn HirDatabase) -> Vec<Crate> { | ||
179 | db.crate_graph().iter().map(|id| Crate { id }).collect() | ||
180 | } | ||
181 | |||
182 | /// Try to get the root URL of the documentation of a crate. | ||
183 | pub fn get_html_root_url(self: &Crate, db: &dyn HirDatabase) -> Option<String> { | ||
184 | // Look for #![doc(html_root_url = "...")] | ||
185 | let attrs = db.attrs(AttrDefId::ModuleId(self.root_module(db).into())); | ||
186 | let doc_attr_q = attrs.by_key("doc"); | ||
187 | |||
188 | if !doc_attr_q.exists() { | ||
189 | return None; | ||
190 | } | ||
191 | |||
192 | let doc_url = doc_attr_q.tt_values().map(|tt| { | ||
193 | let name = tt.token_trees.iter() | ||
194 | .skip_while(|tt| !matches!(tt, TokenTree::Leaf(Leaf::Ident(Ident{text: ref ident, ..})) if ident == "html_root_url")) | ||
195 | .skip(2) | ||
196 | .next(); | ||
197 | |||
198 | match name { | ||
199 | Some(TokenTree::Leaf(Leaf::Literal(Literal{ref text, ..}))) => Some(text), | ||
200 | _ => None | ||
201 | } | ||
202 | }).flat_map(|t| t).next(); | ||
203 | |||
204 | doc_url.map(|s| s.trim_matches('"').trim_end_matches('/').to_owned() + "/") | ||
205 | } | ||
206 | } | ||
207 | |||
208 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
209 | pub struct Module { | ||
210 | pub(crate) id: ModuleId, | ||
211 | } | ||
212 | |||
213 | /// The defs which can be visible in the module. | ||
214 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
215 | pub enum ModuleDef { | ||
216 | Module(Module), | ||
217 | Function(Function), | ||
218 | Adt(Adt), | ||
219 | // Can't be directly declared, but can be imported. | ||
220 | Variant(Variant), | ||
221 | Const(Const), | ||
222 | Static(Static), | ||
223 | Trait(Trait), | ||
224 | TypeAlias(TypeAlias), | ||
225 | BuiltinType(BuiltinType), | ||
226 | } | ||
227 | impl_from!( | ||
228 | Module, | ||
229 | Function, | ||
230 | Adt(Struct, Enum, Union), | ||
231 | Variant, | ||
232 | Const, | ||
233 | Static, | ||
234 | Trait, | ||
235 | TypeAlias, | ||
236 | BuiltinType | ||
237 | for ModuleDef | ||
238 | ); | ||
239 | |||
240 | impl From<VariantDef> for ModuleDef { | ||
241 | fn from(var: VariantDef) -> Self { | ||
242 | match var { | ||
243 | VariantDef::Struct(t) => Adt::from(t).into(), | ||
244 | VariantDef::Union(t) => Adt::from(t).into(), | ||
245 | VariantDef::Variant(t) => t.into(), | ||
246 | } | ||
247 | } | ||
248 | } | ||
249 | |||
250 | impl ModuleDef { | ||
251 | pub fn module(self, db: &dyn HirDatabase) -> Option<Module> { | ||
252 | match self { | ||
253 | ModuleDef::Module(it) => it.parent(db), | ||
254 | ModuleDef::Function(it) => Some(it.module(db)), | ||
255 | ModuleDef::Adt(it) => Some(it.module(db)), | ||
256 | ModuleDef::Variant(it) => Some(it.module(db)), | ||
257 | ModuleDef::Const(it) => Some(it.module(db)), | ||
258 | ModuleDef::Static(it) => Some(it.module(db)), | ||
259 | ModuleDef::Trait(it) => Some(it.module(db)), | ||
260 | ModuleDef::TypeAlias(it) => Some(it.module(db)), | ||
261 | ModuleDef::BuiltinType(_) => None, | ||
262 | } | ||
263 | } | ||
264 | |||
265 | pub fn canonical_path(&self, db: &dyn HirDatabase) -> Option<String> { | ||
266 | let mut segments = Vec::new(); | ||
267 | segments.push(self.name(db)?.to_string()); | ||
268 | for m in self.module(db)?.path_to_root(db) { | ||
269 | segments.extend(m.name(db).map(|it| it.to_string())) | ||
270 | } | ||
271 | segments.reverse(); | ||
272 | Some(segments.join("::")) | ||
273 | } | ||
274 | |||
275 | pub fn definition_visibility(&self, db: &dyn HirDatabase) -> Option<Visibility> { | ||
276 | let module = match self { | ||
277 | ModuleDef::Module(it) => it.parent(db)?, | ||
278 | ModuleDef::Function(it) => return Some(it.visibility(db)), | ||
279 | ModuleDef::Adt(it) => it.module(db), | ||
280 | ModuleDef::Variant(it) => { | ||
281 | let parent = it.parent_enum(db); | ||
282 | let module = it.module(db); | ||
283 | return module.visibility_of(db, &ModuleDef::Adt(Adt::Enum(parent))); | ||
284 | } | ||
285 | ModuleDef::Const(it) => return Some(it.visibility(db)), | ||
286 | ModuleDef::Static(it) => it.module(db), | ||
287 | ModuleDef::Trait(it) => it.module(db), | ||
288 | ModuleDef::TypeAlias(it) => return Some(it.visibility(db)), | ||
289 | ModuleDef::BuiltinType(_) => return None, | ||
290 | }; | ||
291 | |||
292 | module.visibility_of(db, self) | ||
293 | } | ||
294 | |||
295 | pub fn name(self, db: &dyn HirDatabase) -> Option<Name> { | ||
296 | match self { | ||
297 | ModuleDef::Adt(it) => Some(it.name(db)), | ||
298 | ModuleDef::Trait(it) => Some(it.name(db)), | ||
299 | ModuleDef::Function(it) => Some(it.name(db)), | ||
300 | ModuleDef::Variant(it) => Some(it.name(db)), | ||
301 | ModuleDef::TypeAlias(it) => Some(it.name(db)), | ||
302 | ModuleDef::Module(it) => it.name(db), | ||
303 | ModuleDef::Const(it) => it.name(db), | ||
304 | ModuleDef::Static(it) => it.name(db), | ||
305 | |||
306 | ModuleDef::BuiltinType(it) => Some(it.name()), | ||
307 | } | ||
308 | } | ||
309 | |||
310 | pub fn diagnostics(self, db: &dyn HirDatabase, sink: &mut DiagnosticSink) { | ||
311 | let id = match self { | ||
312 | ModuleDef::Adt(it) => match it { | ||
313 | Adt::Struct(it) => it.id.into(), | ||
314 | Adt::Enum(it) => it.id.into(), | ||
315 | Adt::Union(it) => it.id.into(), | ||
316 | }, | ||
317 | ModuleDef::Trait(it) => it.id.into(), | ||
318 | ModuleDef::Function(it) => it.id.into(), | ||
319 | ModuleDef::TypeAlias(it) => it.id.into(), | ||
320 | ModuleDef::Module(it) => it.id.into(), | ||
321 | ModuleDef::Const(it) => it.id.into(), | ||
322 | ModuleDef::Static(it) => it.id.into(), | ||
323 | _ => return, | ||
324 | }; | ||
325 | |||
326 | let module = match self.module(db) { | ||
327 | Some(it) => it, | ||
328 | None => return, | ||
329 | }; | ||
330 | |||
331 | hir_ty::diagnostics::validate_module_item(db, module.id.krate(), id, sink) | ||
332 | } | ||
333 | } | ||
334 | |||
335 | impl Module { | ||
336 | /// Name of this module. | ||
337 | pub fn name(self, db: &dyn HirDatabase) -> Option<Name> { | ||
338 | let def_map = self.id.def_map(db.upcast()); | ||
339 | let parent = def_map[self.id.local_id].parent?; | ||
340 | def_map[parent].children.iter().find_map(|(name, module_id)| { | ||
341 | if *module_id == self.id.local_id { | ||
342 | Some(name.clone()) | ||
343 | } else { | ||
344 | None | ||
345 | } | ||
346 | }) | ||
347 | } | ||
348 | |||
349 | /// Returns the crate this module is part of. | ||
350 | pub fn krate(self) -> Crate { | ||
351 | Crate { id: self.id.krate() } | ||
352 | } | ||
353 | |||
354 | /// Topmost parent of this module. Every module has a `crate_root`, but some | ||
355 | /// might be missing `krate`. This can happen if a module's file is not included | ||
356 | /// in the module tree of any target in `Cargo.toml`. | ||
357 | pub fn crate_root(self, db: &dyn HirDatabase) -> Module { | ||
358 | let def_map = db.crate_def_map(self.id.krate()); | ||
359 | Module { id: def_map.module_id(def_map.root()) } | ||
360 | } | ||
361 | |||
362 | /// Iterates over all child modules. | ||
363 | pub fn children(self, db: &dyn HirDatabase) -> impl Iterator<Item = Module> { | ||
364 | let def_map = self.id.def_map(db.upcast()); | ||
365 | let children = def_map[self.id.local_id] | ||
366 | .children | ||
367 | .iter() | ||
368 | .map(|(_, module_id)| Module { id: def_map.module_id(*module_id) }) | ||
369 | .collect::<Vec<_>>(); | ||
370 | children.into_iter() | ||
371 | } | ||
372 | |||
373 | /// Finds a parent module. | ||
374 | pub fn parent(self, db: &dyn HirDatabase) -> Option<Module> { | ||
375 | // FIXME: handle block expressions as modules (their parent is in a different DefMap) | ||
376 | let def_map = self.id.def_map(db.upcast()); | ||
377 | let parent_id = def_map[self.id.local_id].parent?; | ||
378 | Some(Module { id: def_map.module_id(parent_id) }) | ||
379 | } | ||
380 | |||
381 | pub fn path_to_root(self, db: &dyn HirDatabase) -> Vec<Module> { | ||
382 | let mut res = vec![self]; | ||
383 | let mut curr = self; | ||
384 | while let Some(next) = curr.parent(db) { | ||
385 | res.push(next); | ||
386 | curr = next | ||
387 | } | ||
388 | res | ||
389 | } | ||
390 | |||
391 | /// Returns a `ModuleScope`: a set of items, visible in this module. | ||
392 | pub fn scope( | ||
393 | self, | ||
394 | db: &dyn HirDatabase, | ||
395 | visible_from: Option<Module>, | ||
396 | ) -> Vec<(Name, ScopeDef)> { | ||
397 | self.id.def_map(db.upcast())[self.id.local_id] | ||
398 | .scope | ||
399 | .entries() | ||
400 | .filter_map(|(name, def)| { | ||
401 | if let Some(m) = visible_from { | ||
402 | let filtered = | ||
403 | def.filter_visibility(|vis| vis.is_visible_from(db.upcast(), m.id)); | ||
404 | if filtered.is_none() && !def.is_none() { | ||
405 | None | ||
406 | } else { | ||
407 | Some((name, filtered)) | ||
408 | } | ||
409 | } else { | ||
410 | Some((name, def)) | ||
411 | } | ||
412 | }) | ||
413 | .flat_map(|(name, def)| { | ||
414 | ScopeDef::all_items(def).into_iter().map(move |item| (name.clone(), item)) | ||
415 | }) | ||
416 | .collect() | ||
417 | } | ||
418 | |||
419 | pub fn visibility_of(self, db: &dyn HirDatabase, def: &ModuleDef) -> Option<Visibility> { | ||
420 | self.id.def_map(db.upcast())[self.id.local_id].scope.visibility_of(def.clone().into()) | ||
421 | } | ||
422 | |||
423 | pub fn diagnostics(self, db: &dyn HirDatabase, sink: &mut DiagnosticSink) { | ||
424 | let _p = profile::span("Module::diagnostics").detail(|| { | ||
425 | format!("{:?}", self.name(db).map_or("<unknown>".into(), |name| name.to_string())) | ||
426 | }); | ||
427 | let def_map = self.id.def_map(db.upcast()); | ||
428 | def_map.add_diagnostics(db.upcast(), self.id.local_id, sink); | ||
429 | for decl in self.declarations(db) { | ||
430 | match decl { | ||
431 | crate::ModuleDef::Function(f) => f.diagnostics(db, sink), | ||
432 | crate::ModuleDef::Module(m) => { | ||
433 | // Only add diagnostics from inline modules | ||
434 | if def_map[m.id.local_id].origin.is_inline() { | ||
435 | m.diagnostics(db, sink) | ||
436 | } | ||
437 | } | ||
438 | _ => { | ||
439 | decl.diagnostics(db, sink); | ||
440 | } | ||
441 | } | ||
442 | } | ||
443 | |||
444 | for impl_def in self.impl_defs(db) { | ||
445 | for item in impl_def.items(db) { | ||
446 | if let AssocItem::Function(f) = item { | ||
447 | f.diagnostics(db, sink); | ||
448 | } | ||
449 | } | ||
450 | } | ||
451 | } | ||
452 | |||
453 | pub fn declarations(self, db: &dyn HirDatabase) -> Vec<ModuleDef> { | ||
454 | let def_map = self.id.def_map(db.upcast()); | ||
455 | def_map[self.id.local_id].scope.declarations().map(ModuleDef::from).collect() | ||
456 | } | ||
457 | |||
458 | pub fn impl_defs(self, db: &dyn HirDatabase) -> Vec<Impl> { | ||
459 | let def_map = self.id.def_map(db.upcast()); | ||
460 | def_map[self.id.local_id].scope.impls().map(Impl::from).collect() | ||
461 | } | ||
462 | |||
463 | /// Finds a path that can be used to refer to the given item from within | ||
464 | /// this module, if possible. | ||
465 | pub fn find_use_path(self, db: &dyn DefDatabase, item: impl Into<ItemInNs>) -> Option<ModPath> { | ||
466 | hir_def::find_path::find_path(db, item.into(), self.into()) | ||
467 | } | ||
468 | |||
469 | /// Finds a path that can be used to refer to the given item from within | ||
470 | /// this module, if possible. This is used for returning import paths for use-statements. | ||
471 | pub fn find_use_path_prefixed( | ||
472 | self, | ||
473 | db: &dyn DefDatabase, | ||
474 | item: impl Into<ItemInNs>, | ||
475 | prefix_kind: PrefixKind, | ||
476 | ) -> Option<ModPath> { | ||
477 | hir_def::find_path::find_path_prefixed(db, item.into(), self.into(), prefix_kind) | ||
478 | } | ||
479 | } | ||
480 | |||
481 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
482 | pub struct Field { | ||
483 | pub(crate) parent: VariantDef, | ||
484 | pub(crate) id: LocalFieldId, | ||
485 | } | ||
486 | |||
487 | #[derive(Debug, PartialEq, Eq)] | ||
488 | pub enum FieldSource { | ||
489 | Named(ast::RecordField), | ||
490 | Pos(ast::TupleField), | ||
491 | } | ||
492 | |||
493 | impl Field { | ||
494 | pub fn name(&self, db: &dyn HirDatabase) -> Name { | ||
495 | self.parent.variant_data(db).fields()[self.id].name.clone() | ||
496 | } | ||
497 | |||
498 | /// Returns the type as in the signature of the struct (i.e., with | ||
499 | /// placeholder types for type parameters). This is good for showing | ||
500 | /// signature help, but not so good to actually get the type of the field | ||
501 | /// when you actually have a variable of the struct. | ||
502 | pub fn signature_ty(&self, db: &dyn HirDatabase) -> Type { | ||
503 | let var_id = self.parent.into(); | ||
504 | let generic_def_id: GenericDefId = match self.parent { | ||
505 | VariantDef::Struct(it) => it.id.into(), | ||
506 | VariantDef::Union(it) => it.id.into(), | ||
507 | VariantDef::Variant(it) => it.parent.id.into(), | ||
508 | }; | ||
509 | let substs = Substs::type_params(db, generic_def_id); | ||
510 | let ty = db.field_types(var_id)[self.id].clone().subst(&substs); | ||
511 | Type::new(db, self.parent.module(db).id.krate(), var_id, ty) | ||
512 | } | ||
513 | |||
514 | pub fn parent_def(&self, _db: &dyn HirDatabase) -> VariantDef { | ||
515 | self.parent | ||
516 | } | ||
517 | } | ||
518 | |||
519 | impl HasVisibility for Field { | ||
520 | fn visibility(&self, db: &dyn HirDatabase) -> Visibility { | ||
521 | let variant_data = self.parent.variant_data(db); | ||
522 | let visibility = &variant_data.fields()[self.id].visibility; | ||
523 | let parent_id: hir_def::VariantId = self.parent.into(); | ||
524 | visibility.resolve(db.upcast(), &parent_id.resolver(db.upcast())) | ||
525 | } | ||
526 | } | ||
527 | |||
528 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
529 | pub struct Struct { | ||
530 | pub(crate) id: StructId, | ||
531 | } | ||
532 | |||
533 | impl Struct { | ||
534 | pub fn module(self, db: &dyn HirDatabase) -> Module { | ||
535 | Module { id: self.id.lookup(db.upcast()).container.module(db.upcast()) } | ||
536 | } | ||
537 | |||
538 | pub fn krate(self, db: &dyn HirDatabase) -> Option<Crate> { | ||
539 | Some(self.module(db).krate()) | ||
540 | } | ||
541 | |||
542 | pub fn name(self, db: &dyn HirDatabase) -> Name { | ||
543 | db.struct_data(self.id).name.clone() | ||
544 | } | ||
545 | |||
546 | pub fn fields(self, db: &dyn HirDatabase) -> Vec<Field> { | ||
547 | db.struct_data(self.id) | ||
548 | .variant_data | ||
549 | .fields() | ||
550 | .iter() | ||
551 | .map(|(id, _)| Field { parent: self.into(), id }) | ||
552 | .collect() | ||
553 | } | ||
554 | |||
555 | pub fn ty(self, db: &dyn HirDatabase) -> Type { | ||
556 | Type::from_def( | ||
557 | db, | ||
558 | self.id.lookup(db.upcast()).container.module(db.upcast()).krate(), | ||
559 | self.id, | ||
560 | ) | ||
561 | } | ||
562 | |||
563 | pub fn repr(self, db: &dyn HirDatabase) -> Option<ReprKind> { | ||
564 | db.struct_data(self.id).repr.clone() | ||
565 | } | ||
566 | |||
567 | pub fn kind(self, db: &dyn HirDatabase) -> StructKind { | ||
568 | self.variant_data(db).kind() | ||
569 | } | ||
570 | |||
571 | fn variant_data(self, db: &dyn HirDatabase) -> Arc<VariantData> { | ||
572 | db.struct_data(self.id).variant_data.clone() | ||
573 | } | ||
574 | } | ||
575 | |||
576 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
577 | pub struct Union { | ||
578 | pub(crate) id: UnionId, | ||
579 | } | ||
580 | |||
581 | impl Union { | ||
582 | pub fn name(self, db: &dyn HirDatabase) -> Name { | ||
583 | db.union_data(self.id).name.clone() | ||
584 | } | ||
585 | |||
586 | pub fn module(self, db: &dyn HirDatabase) -> Module { | ||
587 | Module { id: self.id.lookup(db.upcast()).container.module(db.upcast()) } | ||
588 | } | ||
589 | |||
590 | pub fn ty(self, db: &dyn HirDatabase) -> Type { | ||
591 | Type::from_def( | ||
592 | db, | ||
593 | self.id.lookup(db.upcast()).container.module(db.upcast()).krate(), | ||
594 | self.id, | ||
595 | ) | ||
596 | } | ||
597 | |||
598 | pub fn fields(self, db: &dyn HirDatabase) -> Vec<Field> { | ||
599 | db.union_data(self.id) | ||
600 | .variant_data | ||
601 | .fields() | ||
602 | .iter() | ||
603 | .map(|(id, _)| Field { parent: self.into(), id }) | ||
604 | .collect() | ||
605 | } | ||
606 | |||
607 | fn variant_data(self, db: &dyn HirDatabase) -> Arc<VariantData> { | ||
608 | db.union_data(self.id).variant_data.clone() | ||
609 | } | ||
610 | } | ||
611 | |||
612 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
613 | pub struct Enum { | ||
614 | pub(crate) id: EnumId, | ||
615 | } | ||
616 | |||
617 | impl Enum { | ||
618 | pub fn module(self, db: &dyn HirDatabase) -> Module { | ||
619 | Module { id: self.id.lookup(db.upcast()).container.module(db.upcast()) } | ||
620 | } | ||
621 | |||
622 | pub fn krate(self, db: &dyn HirDatabase) -> Option<Crate> { | ||
623 | Some(self.module(db).krate()) | ||
624 | } | ||
625 | |||
626 | pub fn name(self, db: &dyn HirDatabase) -> Name { | ||
627 | db.enum_data(self.id).name.clone() | ||
628 | } | ||
629 | |||
630 | pub fn variants(self, db: &dyn HirDatabase) -> Vec<Variant> { | ||
631 | db.enum_data(self.id).variants.iter().map(|(id, _)| Variant { parent: self, id }).collect() | ||
632 | } | ||
633 | |||
634 | pub fn ty(self, db: &dyn HirDatabase) -> Type { | ||
635 | Type::from_def( | ||
636 | db, | ||
637 | self.id.lookup(db.upcast()).container.module(db.upcast()).krate(), | ||
638 | self.id, | ||
639 | ) | ||
640 | } | ||
641 | } | ||
642 | |||
643 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
644 | pub struct Variant { | ||
645 | pub(crate) parent: Enum, | ||
646 | pub(crate) id: LocalEnumVariantId, | ||
647 | } | ||
648 | |||
649 | impl Variant { | ||
650 | pub fn module(self, db: &dyn HirDatabase) -> Module { | ||
651 | self.parent.module(db) | ||
652 | } | ||
653 | pub fn parent_enum(self, _db: &dyn HirDatabase) -> Enum { | ||
654 | self.parent | ||
655 | } | ||
656 | |||
657 | pub fn name(self, db: &dyn HirDatabase) -> Name { | ||
658 | db.enum_data(self.parent.id).variants[self.id].name.clone() | ||
659 | } | ||
660 | |||
661 | pub fn fields(self, db: &dyn HirDatabase) -> Vec<Field> { | ||
662 | self.variant_data(db) | ||
663 | .fields() | ||
664 | .iter() | ||
665 | .map(|(id, _)| Field { parent: self.into(), id }) | ||
666 | .collect() | ||
667 | } | ||
668 | |||
669 | pub fn kind(self, db: &dyn HirDatabase) -> StructKind { | ||
670 | self.variant_data(db).kind() | ||
671 | } | ||
672 | |||
673 | pub(crate) fn variant_data(self, db: &dyn HirDatabase) -> Arc<VariantData> { | ||
674 | db.enum_data(self.parent.id).variants[self.id].variant_data.clone() | ||
675 | } | ||
676 | } | ||
677 | |||
678 | /// A Data Type | ||
679 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] | ||
680 | pub enum Adt { | ||
681 | Struct(Struct), | ||
682 | Union(Union), | ||
683 | Enum(Enum), | ||
684 | } | ||
685 | impl_from!(Struct, Union, Enum for Adt); | ||
686 | |||
687 | impl Adt { | ||
688 | pub fn has_non_default_type_params(self, db: &dyn HirDatabase) -> bool { | ||
689 | let subst = db.generic_defaults(self.into()); | ||
690 | subst.iter().any(|ty| &ty.value == &Ty::Unknown) | ||
691 | } | ||
692 | |||
693 | /// Turns this ADT into a type. Any type parameters of the ADT will be | ||
694 | /// turned into unknown types, which is good for e.g. finding the most | ||
695 | /// general set of completions, but will not look very nice when printed. | ||
696 | pub fn ty(self, db: &dyn HirDatabase) -> Type { | ||
697 | let id = AdtId::from(self); | ||
698 | Type::from_def(db, id.module(db.upcast()).krate(), id) | ||
699 | } | ||
700 | |||
701 | pub fn module(self, db: &dyn HirDatabase) -> Module { | ||
702 | match self { | ||
703 | Adt::Struct(s) => s.module(db), | ||
704 | Adt::Union(s) => s.module(db), | ||
705 | Adt::Enum(e) => e.module(db), | ||
706 | } | ||
707 | } | ||
708 | |||
709 | pub fn krate(self, db: &dyn HirDatabase) -> Option<Crate> { | ||
710 | Some(self.module(db).krate()) | ||
711 | } | ||
712 | |||
713 | pub fn name(self, db: &dyn HirDatabase) -> Name { | ||
714 | match self { | ||
715 | Adt::Struct(s) => s.name(db), | ||
716 | Adt::Union(u) => u.name(db), | ||
717 | Adt::Enum(e) => e.name(db), | ||
718 | } | ||
719 | } | ||
720 | } | ||
721 | |||
722 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] | ||
723 | pub enum VariantDef { | ||
724 | Struct(Struct), | ||
725 | Union(Union), | ||
726 | Variant(Variant), | ||
727 | } | ||
728 | impl_from!(Struct, Union, Variant for VariantDef); | ||
729 | |||
730 | impl VariantDef { | ||
731 | pub fn fields(self, db: &dyn HirDatabase) -> Vec<Field> { | ||
732 | match self { | ||
733 | VariantDef::Struct(it) => it.fields(db), | ||
734 | VariantDef::Union(it) => it.fields(db), | ||
735 | VariantDef::Variant(it) => it.fields(db), | ||
736 | } | ||
737 | } | ||
738 | |||
739 | pub fn module(self, db: &dyn HirDatabase) -> Module { | ||
740 | match self { | ||
741 | VariantDef::Struct(it) => it.module(db), | ||
742 | VariantDef::Union(it) => it.module(db), | ||
743 | VariantDef::Variant(it) => it.module(db), | ||
744 | } | ||
745 | } | ||
746 | |||
747 | pub fn name(&self, db: &dyn HirDatabase) -> Name { | ||
748 | match self { | ||
749 | VariantDef::Struct(s) => s.name(db), | ||
750 | VariantDef::Union(u) => u.name(db), | ||
751 | VariantDef::Variant(e) => e.name(db), | ||
752 | } | ||
753 | } | ||
754 | |||
755 | pub(crate) fn variant_data(self, db: &dyn HirDatabase) -> Arc<VariantData> { | ||
756 | match self { | ||
757 | VariantDef::Struct(it) => it.variant_data(db), | ||
758 | VariantDef::Union(it) => it.variant_data(db), | ||
759 | VariantDef::Variant(it) => it.variant_data(db), | ||
760 | } | ||
761 | } | ||
762 | } | ||
763 | |||
764 | /// The defs which have a body. | ||
765 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
766 | pub enum DefWithBody { | ||
767 | Function(Function), | ||
768 | Static(Static), | ||
769 | Const(Const), | ||
770 | } | ||
771 | impl_from!(Function, Const, Static for DefWithBody); | ||
772 | |||
773 | impl DefWithBody { | ||
774 | pub fn module(self, db: &dyn HirDatabase) -> Module { | ||
775 | match self { | ||
776 | DefWithBody::Const(c) => c.module(db), | ||
777 | DefWithBody::Function(f) => f.module(db), | ||
778 | DefWithBody::Static(s) => s.module(db), | ||
779 | } | ||
780 | } | ||
781 | |||
782 | pub fn name(self, db: &dyn HirDatabase) -> Option<Name> { | ||
783 | match self { | ||
784 | DefWithBody::Function(f) => Some(f.name(db)), | ||
785 | DefWithBody::Static(s) => s.name(db), | ||
786 | DefWithBody::Const(c) => c.name(db), | ||
787 | } | ||
788 | } | ||
789 | } | ||
790 | |||
791 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
792 | pub struct Function { | ||
793 | pub(crate) id: FunctionId, | ||
794 | } | ||
795 | |||
796 | impl Function { | ||
797 | pub fn module(self, db: &dyn HirDatabase) -> Module { | ||
798 | self.id.lookup(db.upcast()).module(db.upcast()).into() | ||
799 | } | ||
800 | |||
801 | pub fn krate(self, db: &dyn HirDatabase) -> Option<Crate> { | ||
802 | Some(self.module(db).krate()) | ||
803 | } | ||
804 | |||
805 | pub fn name(self, db: &dyn HirDatabase) -> Name { | ||
806 | db.function_data(self.id).name.clone() | ||
807 | } | ||
808 | |||
809 | /// Get this function's return type | ||
810 | pub fn ret_type(self, db: &dyn HirDatabase) -> Type { | ||
811 | let resolver = self.id.resolver(db.upcast()); | ||
812 | let ret_type = &db.function_data(self.id).ret_type; | ||
813 | let ctx = hir_ty::TyLoweringContext::new(db, &resolver); | ||
814 | let environment = TraitEnvironment::lower(db, &resolver); | ||
815 | Type { | ||
816 | krate: self.id.lookup(db.upcast()).container.module(db.upcast()).krate(), | ||
817 | ty: InEnvironment { value: Ty::from_hir_ext(&ctx, ret_type).0, environment }, | ||
818 | } | ||
819 | } | ||
820 | |||
821 | pub fn self_param(self, db: &dyn HirDatabase) -> Option<SelfParam> { | ||
822 | if !db.function_data(self.id).has_self_param { | ||
823 | return None; | ||
824 | } | ||
825 | Some(SelfParam { func: self.id }) | ||
826 | } | ||
827 | |||
828 | pub fn assoc_fn_params(self, db: &dyn HirDatabase) -> Vec<Param> { | ||
829 | let resolver = self.id.resolver(db.upcast()); | ||
830 | let ctx = hir_ty::TyLoweringContext::new(db, &resolver); | ||
831 | let environment = TraitEnvironment::lower(db, &resolver); | ||
832 | db.function_data(self.id) | ||
833 | .params | ||
834 | .iter() | ||
835 | .map(|type_ref| { | ||
836 | let ty = Type { | ||
837 | krate: self.id.lookup(db.upcast()).container.module(db.upcast()).krate(), | ||
838 | ty: InEnvironment { | ||
839 | value: Ty::from_hir_ext(&ctx, type_ref).0, | ||
840 | environment: environment.clone(), | ||
841 | }, | ||
842 | }; | ||
843 | Param { ty } | ||
844 | }) | ||
845 | .collect() | ||
846 | } | ||
847 | pub fn method_params(self, db: &dyn HirDatabase) -> Option<Vec<Param>> { | ||
848 | if self.self_param(db).is_none() { | ||
849 | return None; | ||
850 | } | ||
851 | let mut res = self.assoc_fn_params(db); | ||
852 | res.remove(0); | ||
853 | Some(res) | ||
854 | } | ||
855 | |||
856 | pub fn is_unsafe(self, db: &dyn HirDatabase) -> bool { | ||
857 | db.function_data(self.id).is_unsafe | ||
858 | } | ||
859 | |||
860 | pub fn diagnostics(self, db: &dyn HirDatabase, sink: &mut DiagnosticSink) { | ||
861 | let krate = self.module(db).id.krate(); | ||
862 | hir_def::diagnostics::validate_body(db.upcast(), self.id.into(), sink); | ||
863 | hir_ty::diagnostics::validate_module_item(db, krate, self.id.into(), sink); | ||
864 | hir_ty::diagnostics::validate_body(db, self.id.into(), sink); | ||
865 | } | ||
866 | |||
867 | /// Whether this function declaration has a definition. | ||
868 | /// | ||
869 | /// This is false in the case of required (not provided) trait methods. | ||
870 | pub fn has_body(self, db: &dyn HirDatabase) -> bool { | ||
871 | db.function_data(self.id).has_body | ||
872 | } | ||
873 | |||
874 | /// A textual representation of the HIR of this function for debugging purposes. | ||
875 | pub fn debug_hir(self, db: &dyn HirDatabase) -> String { | ||
876 | let body = db.body(self.id.into()); | ||
877 | |||
878 | let mut result = String::new(); | ||
879 | format_to!(result, "HIR expressions in the body of `{}`:\n", self.name(db)); | ||
880 | for (id, expr) in body.exprs.iter() { | ||
881 | format_to!(result, "{:?}: {:?}\n", id, expr); | ||
882 | } | ||
883 | |||
884 | result | ||
885 | } | ||
886 | } | ||
887 | |||
888 | // Note: logically, this belongs to `hir_ty`, but we are not using it there yet. | ||
889 | pub enum Access { | ||
890 | Shared, | ||
891 | Exclusive, | ||
892 | Owned, | ||
893 | } | ||
894 | |||
895 | impl From<hir_ty::Mutability> for Access { | ||
896 | fn from(mutability: hir_ty::Mutability) -> Access { | ||
897 | match mutability { | ||
898 | hir_ty::Mutability::Not => Access::Shared, | ||
899 | hir_ty::Mutability::Mut => Access::Exclusive, | ||
900 | } | ||
901 | } | ||
902 | } | ||
903 | |||
904 | #[derive(Debug)] | ||
905 | pub struct Param { | ||
906 | ty: Type, | ||
907 | } | ||
908 | |||
909 | impl Param { | ||
910 | pub fn ty(&self) -> &Type { | ||
911 | &self.ty | ||
912 | } | ||
913 | } | ||
914 | |||
915 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
916 | pub struct SelfParam { | ||
917 | func: FunctionId, | ||
918 | } | ||
919 | |||
920 | impl SelfParam { | ||
921 | pub fn access(self, db: &dyn HirDatabase) -> Access { | ||
922 | let func_data = db.function_data(self.func); | ||
923 | func_data | ||
924 | .params | ||
925 | .first() | ||
926 | .map(|param| match *param { | ||
927 | TypeRef::Reference(.., mutability) => match mutability { | ||
928 | hir_def::type_ref::Mutability::Shared => Access::Shared, | ||
929 | hir_def::type_ref::Mutability::Mut => Access::Exclusive, | ||
930 | }, | ||
931 | _ => Access::Owned, | ||
932 | }) | ||
933 | .unwrap_or(Access::Owned) | ||
934 | } | ||
935 | } | ||
936 | |||
937 | impl HasVisibility for Function { | ||
938 | fn visibility(&self, db: &dyn HirDatabase) -> Visibility { | ||
939 | let function_data = db.function_data(self.id); | ||
940 | let visibility = &function_data.visibility; | ||
941 | visibility.resolve(db.upcast(), &self.id.resolver(db.upcast())) | ||
942 | } | ||
943 | } | ||
944 | |||
945 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
946 | pub struct Const { | ||
947 | pub(crate) id: ConstId, | ||
948 | } | ||
949 | |||
950 | impl Const { | ||
951 | pub fn module(self, db: &dyn HirDatabase) -> Module { | ||
952 | Module { id: self.id.lookup(db.upcast()).module(db.upcast()) } | ||
953 | } | ||
954 | |||
955 | pub fn krate(self, db: &dyn HirDatabase) -> Option<Crate> { | ||
956 | Some(self.module(db).krate()) | ||
957 | } | ||
958 | |||
959 | pub fn name(self, db: &dyn HirDatabase) -> Option<Name> { | ||
960 | db.const_data(self.id).name.clone() | ||
961 | } | ||
962 | } | ||
963 | |||
964 | impl HasVisibility for Const { | ||
965 | fn visibility(&self, db: &dyn HirDatabase) -> Visibility { | ||
966 | let function_data = db.const_data(self.id); | ||
967 | let visibility = &function_data.visibility; | ||
968 | visibility.resolve(db.upcast(), &self.id.resolver(db.upcast())) | ||
969 | } | ||
970 | } | ||
971 | |||
972 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
973 | pub struct Static { | ||
974 | pub(crate) id: StaticId, | ||
975 | } | ||
976 | |||
977 | impl Static { | ||
978 | pub fn module(self, db: &dyn HirDatabase) -> Module { | ||
979 | Module { id: self.id.lookup(db.upcast()).module(db.upcast()) } | ||
980 | } | ||
981 | |||
982 | pub fn krate(self, db: &dyn HirDatabase) -> Option<Crate> { | ||
983 | Some(self.module(db).krate()) | ||
984 | } | ||
985 | |||
986 | pub fn name(self, db: &dyn HirDatabase) -> Option<Name> { | ||
987 | db.static_data(self.id).name.clone() | ||
988 | } | ||
989 | |||
990 | pub fn is_mut(self, db: &dyn HirDatabase) -> bool { | ||
991 | db.static_data(self.id).mutable | ||
992 | } | ||
993 | } | ||
994 | |||
995 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
996 | pub struct Trait { | ||
997 | pub(crate) id: TraitId, | ||
998 | } | ||
999 | |||
1000 | impl Trait { | ||
1001 | pub fn module(self, db: &dyn HirDatabase) -> Module { | ||
1002 | Module { id: self.id.lookup(db.upcast()).container.module(db.upcast()) } | ||
1003 | } | ||
1004 | |||
1005 | pub fn name(self, db: &dyn HirDatabase) -> Name { | ||
1006 | db.trait_data(self.id).name.clone() | ||
1007 | } | ||
1008 | |||
1009 | pub fn items(self, db: &dyn HirDatabase) -> Vec<AssocItem> { | ||
1010 | db.trait_data(self.id).items.iter().map(|(_name, it)| (*it).into()).collect() | ||
1011 | } | ||
1012 | |||
1013 | pub fn is_auto(self, db: &dyn HirDatabase) -> bool { | ||
1014 | db.trait_data(self.id).auto | ||
1015 | } | ||
1016 | } | ||
1017 | |||
1018 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
1019 | pub struct TypeAlias { | ||
1020 | pub(crate) id: TypeAliasId, | ||
1021 | } | ||
1022 | |||
1023 | impl TypeAlias { | ||
1024 | pub fn has_non_default_type_params(self, db: &dyn HirDatabase) -> bool { | ||
1025 | let subst = db.generic_defaults(self.id.into()); | ||
1026 | subst.iter().any(|ty| &ty.value == &Ty::Unknown) | ||
1027 | } | ||
1028 | |||
1029 | pub fn module(self, db: &dyn HirDatabase) -> Module { | ||
1030 | Module { id: self.id.lookup(db.upcast()).module(db.upcast()) } | ||
1031 | } | ||
1032 | |||
1033 | pub fn krate(self, db: &dyn HirDatabase) -> Option<Crate> { | ||
1034 | Some(self.module(db).krate()) | ||
1035 | } | ||
1036 | |||
1037 | pub fn type_ref(self, db: &dyn HirDatabase) -> Option<TypeRef> { | ||
1038 | db.type_alias_data(self.id).type_ref.clone() | ||
1039 | } | ||
1040 | |||
1041 | pub fn ty(self, db: &dyn HirDatabase) -> Type { | ||
1042 | Type::from_def(db, self.id.lookup(db.upcast()).module(db.upcast()).krate(), self.id) | ||
1043 | } | ||
1044 | |||
1045 | pub fn name(self, db: &dyn HirDatabase) -> Name { | ||
1046 | db.type_alias_data(self.id).name.clone() | ||
1047 | } | ||
1048 | } | ||
1049 | |||
1050 | impl HasVisibility for TypeAlias { | ||
1051 | fn visibility(&self, db: &dyn HirDatabase) -> Visibility { | ||
1052 | let function_data = db.type_alias_data(self.id); | ||
1053 | let visibility = &function_data.visibility; | ||
1054 | visibility.resolve(db.upcast(), &self.id.resolver(db.upcast())) | ||
1055 | } | ||
1056 | } | ||
1057 | |||
1058 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
1059 | pub struct BuiltinType { | ||
1060 | pub(crate) inner: hir_def::builtin_type::BuiltinType, | ||
1061 | } | ||
1062 | |||
1063 | impl BuiltinType { | ||
1064 | pub fn ty(self, db: &dyn HirDatabase, module: Module) -> Type { | ||
1065 | let resolver = module.id.resolver(db.upcast()); | ||
1066 | Type::new_with_resolver(db, &resolver, Ty::builtin(self.inner)) | ||
1067 | .expect("crate not present in resolver") | ||
1068 | } | ||
1069 | |||
1070 | pub fn name(self) -> Name { | ||
1071 | self.inner.as_name() | ||
1072 | } | ||
1073 | } | ||
1074 | |||
1075 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
1076 | pub struct MacroDef { | ||
1077 | pub(crate) id: MacroDefId, | ||
1078 | } | ||
1079 | |||
1080 | impl MacroDef { | ||
1081 | /// FIXME: right now, this just returns the root module of the crate that | ||
1082 | /// defines this macro. The reasons for this is that macros are expanded | ||
1083 | /// early, in `hir_expand`, where modules simply do not exist yet. | ||
1084 | pub fn module(self, db: &dyn HirDatabase) -> Option<Module> { | ||
1085 | let krate = self.id.krate; | ||
1086 | let def_map = db.crate_def_map(krate); | ||
1087 | let module_id = def_map.root(); | ||
1088 | Some(Module { id: def_map.module_id(module_id) }) | ||
1089 | } | ||
1090 | |||
1091 | /// XXX: this parses the file | ||
1092 | pub fn name(self, db: &dyn HirDatabase) -> Option<Name> { | ||
1093 | self.source(db)?.value.name().map(|it| it.as_name()) | ||
1094 | } | ||
1095 | |||
1096 | /// Indicate it is a proc-macro | ||
1097 | pub fn is_proc_macro(&self) -> bool { | ||
1098 | matches!(self.id.kind, MacroDefKind::ProcMacro(_)) | ||
1099 | } | ||
1100 | |||
1101 | /// Indicate it is a derive macro | ||
1102 | pub fn is_derive_macro(&self) -> bool { | ||
1103 | matches!(self.id.kind, MacroDefKind::ProcMacro(_) | MacroDefKind::BuiltInDerive(_)) | ||
1104 | } | ||
1105 | } | ||
1106 | |||
1107 | /// Invariant: `inner.as_assoc_item(db).is_some()` | ||
1108 | /// We do not actively enforce this invariant. | ||
1109 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] | ||
1110 | pub enum AssocItem { | ||
1111 | Function(Function), | ||
1112 | Const(Const), | ||
1113 | TypeAlias(TypeAlias), | ||
1114 | } | ||
1115 | pub enum AssocItemContainer { | ||
1116 | Trait(Trait), | ||
1117 | Impl(Impl), | ||
1118 | } | ||
1119 | pub trait AsAssocItem { | ||
1120 | fn as_assoc_item(self, db: &dyn HirDatabase) -> Option<AssocItem>; | ||
1121 | } | ||
1122 | |||
1123 | impl AsAssocItem for Function { | ||
1124 | fn as_assoc_item(self, db: &dyn HirDatabase) -> Option<AssocItem> { | ||
1125 | as_assoc_item(db, AssocItem::Function, self.id) | ||
1126 | } | ||
1127 | } | ||
1128 | impl AsAssocItem for Const { | ||
1129 | fn as_assoc_item(self, db: &dyn HirDatabase) -> Option<AssocItem> { | ||
1130 | as_assoc_item(db, AssocItem::Const, self.id) | ||
1131 | } | ||
1132 | } | ||
1133 | impl AsAssocItem for TypeAlias { | ||
1134 | fn as_assoc_item(self, db: &dyn HirDatabase) -> Option<AssocItem> { | ||
1135 | as_assoc_item(db, AssocItem::TypeAlias, self.id) | ||
1136 | } | ||
1137 | } | ||
1138 | impl AsAssocItem for ModuleDef { | ||
1139 | fn as_assoc_item(self, db: &dyn HirDatabase) -> Option<AssocItem> { | ||
1140 | match self { | ||
1141 | ModuleDef::Function(it) => it.as_assoc_item(db), | ||
1142 | ModuleDef::Const(it) => it.as_assoc_item(db), | ||
1143 | ModuleDef::TypeAlias(it) => it.as_assoc_item(db), | ||
1144 | _ => None, | ||
1145 | } | ||
1146 | } | ||
1147 | } | ||
1148 | fn as_assoc_item<ID, DEF, CTOR, AST>(db: &dyn HirDatabase, ctor: CTOR, id: ID) -> Option<AssocItem> | ||
1149 | where | ||
1150 | ID: Lookup<Data = AssocItemLoc<AST>>, | ||
1151 | DEF: From<ID>, | ||
1152 | CTOR: FnOnce(DEF) -> AssocItem, | ||
1153 | AST: ItemTreeNode, | ||
1154 | { | ||
1155 | match id.lookup(db.upcast()).container { | ||
1156 | AssocContainerId::TraitId(_) | AssocContainerId::ImplId(_) => Some(ctor(DEF::from(id))), | ||
1157 | AssocContainerId::ContainerId(_) => None, | ||
1158 | } | ||
1159 | } | ||
1160 | |||
1161 | impl AssocItem { | ||
1162 | pub fn name(self, db: &dyn HirDatabase) -> Option<Name> { | ||
1163 | match self { | ||
1164 | AssocItem::Function(it) => Some(it.name(db)), | ||
1165 | AssocItem::Const(it) => it.name(db), | ||
1166 | AssocItem::TypeAlias(it) => Some(it.name(db)), | ||
1167 | } | ||
1168 | } | ||
1169 | pub fn module(self, db: &dyn HirDatabase) -> Module { | ||
1170 | match self { | ||
1171 | AssocItem::Function(f) => f.module(db), | ||
1172 | AssocItem::Const(c) => c.module(db), | ||
1173 | AssocItem::TypeAlias(t) => t.module(db), | ||
1174 | } | ||
1175 | } | ||
1176 | pub fn container(self, db: &dyn HirDatabase) -> AssocItemContainer { | ||
1177 | let container = match self { | ||
1178 | AssocItem::Function(it) => it.id.lookup(db.upcast()).container, | ||
1179 | AssocItem::Const(it) => it.id.lookup(db.upcast()).container, | ||
1180 | AssocItem::TypeAlias(it) => it.id.lookup(db.upcast()).container, | ||
1181 | }; | ||
1182 | match container { | ||
1183 | AssocContainerId::TraitId(id) => AssocItemContainer::Trait(id.into()), | ||
1184 | AssocContainerId::ImplId(id) => AssocItemContainer::Impl(id.into()), | ||
1185 | AssocContainerId::ContainerId(_) => panic!("invalid AssocItem"), | ||
1186 | } | ||
1187 | } | ||
1188 | |||
1189 | pub fn containing_trait(self, db: &dyn HirDatabase) -> Option<Trait> { | ||
1190 | match self.container(db) { | ||
1191 | AssocItemContainer::Trait(t) => Some(t), | ||
1192 | _ => None, | ||
1193 | } | ||
1194 | } | ||
1195 | } | ||
1196 | |||
1197 | impl HasVisibility for AssocItem { | ||
1198 | fn visibility(&self, db: &dyn HirDatabase) -> Visibility { | ||
1199 | match self { | ||
1200 | AssocItem::Function(f) => f.visibility(db), | ||
1201 | AssocItem::Const(c) => c.visibility(db), | ||
1202 | AssocItem::TypeAlias(t) => t.visibility(db), | ||
1203 | } | ||
1204 | } | ||
1205 | } | ||
1206 | |||
1207 | #[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] | ||
1208 | pub enum GenericDef { | ||
1209 | Function(Function), | ||
1210 | Adt(Adt), | ||
1211 | Trait(Trait), | ||
1212 | TypeAlias(TypeAlias), | ||
1213 | Impl(Impl), | ||
1214 | // enum variants cannot have generics themselves, but their parent enums | ||
1215 | // can, and this makes some code easier to write | ||
1216 | Variant(Variant), | ||
1217 | // consts can have type parameters from their parents (i.e. associated consts of traits) | ||
1218 | Const(Const), | ||
1219 | } | ||
1220 | impl_from!( | ||
1221 | Function, | ||
1222 | Adt(Struct, Enum, Union), | ||
1223 | Trait, | ||
1224 | TypeAlias, | ||
1225 | Impl, | ||
1226 | Variant, | ||
1227 | Const | ||
1228 | for GenericDef | ||
1229 | ); | ||
1230 | |||
1231 | impl GenericDef { | ||
1232 | pub fn params(self, db: &dyn HirDatabase) -> Vec<GenericParam> { | ||
1233 | let generics = db.generic_params(self.into()); | ||
1234 | let ty_params = generics | ||
1235 | .types | ||
1236 | .iter() | ||
1237 | .map(|(local_id, _)| TypeParam { id: TypeParamId { parent: self.into(), local_id } }) | ||
1238 | .map(GenericParam::TypeParam); | ||
1239 | let lt_params = generics | ||
1240 | .lifetimes | ||
1241 | .iter() | ||
1242 | .map(|(local_id, _)| LifetimeParam { | ||
1243 | id: LifetimeParamId { parent: self.into(), local_id }, | ||
1244 | }) | ||
1245 | .map(GenericParam::LifetimeParam); | ||
1246 | let const_params = generics | ||
1247 | .consts | ||
1248 | .iter() | ||
1249 | .map(|(local_id, _)| ConstParam { id: ConstParamId { parent: self.into(), local_id } }) | ||
1250 | .map(GenericParam::ConstParam); | ||
1251 | ty_params.chain(lt_params).chain(const_params).collect() | ||
1252 | } | ||
1253 | |||
1254 | pub fn type_params(self, db: &dyn HirDatabase) -> Vec<TypeParam> { | ||
1255 | let generics = db.generic_params(self.into()); | ||
1256 | generics | ||
1257 | .types | ||
1258 | .iter() | ||
1259 | .map(|(local_id, _)| TypeParam { id: TypeParamId { parent: self.into(), local_id } }) | ||
1260 | .collect() | ||
1261 | } | ||
1262 | } | ||
1263 | |||
1264 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] | ||
1265 | pub struct Local { | ||
1266 | pub(crate) parent: DefWithBodyId, | ||
1267 | pub(crate) pat_id: PatId, | ||
1268 | } | ||
1269 | |||
1270 | impl Local { | ||
1271 | pub fn is_param(self, db: &dyn HirDatabase) -> bool { | ||
1272 | let src = self.source(db); | ||
1273 | match src.value { | ||
1274 | Either::Left(bind_pat) => { | ||
1275 | bind_pat.syntax().ancestors().any(|it| ast::Param::can_cast(it.kind())) | ||
1276 | } | ||
1277 | Either::Right(_self_param) => true, | ||
1278 | } | ||
1279 | } | ||
1280 | |||
1281 | // FIXME: why is this an option? It shouldn't be? | ||
1282 | pub fn name(self, db: &dyn HirDatabase) -> Option<Name> { | ||
1283 | let body = db.body(self.parent.into()); | ||
1284 | match &body[self.pat_id] { | ||
1285 | Pat::Bind { name, .. } => Some(name.clone()), | ||
1286 | _ => None, | ||
1287 | } | ||
1288 | } | ||
1289 | |||
1290 | pub fn is_self(self, db: &dyn HirDatabase) -> bool { | ||
1291 | self.name(db) == Some(name![self]) | ||
1292 | } | ||
1293 | |||
1294 | pub fn is_mut(self, db: &dyn HirDatabase) -> bool { | ||
1295 | let body = db.body(self.parent.into()); | ||
1296 | match &body[self.pat_id] { | ||
1297 | Pat::Bind { mode, .. } => match mode { | ||
1298 | BindingAnnotation::Mutable | BindingAnnotation::RefMut => true, | ||
1299 | _ => false, | ||
1300 | }, | ||
1301 | _ => false, | ||
1302 | } | ||
1303 | } | ||
1304 | |||
1305 | pub fn parent(self, _db: &dyn HirDatabase) -> DefWithBody { | ||
1306 | self.parent.into() | ||
1307 | } | ||
1308 | |||
1309 | pub fn module(self, db: &dyn HirDatabase) -> Module { | ||
1310 | self.parent(db).module(db) | ||
1311 | } | ||
1312 | |||
1313 | pub fn ty(self, db: &dyn HirDatabase) -> Type { | ||
1314 | let def = DefWithBodyId::from(self.parent); | ||
1315 | let infer = db.infer(def); | ||
1316 | let ty = infer[self.pat_id].clone(); | ||
1317 | let krate = def.module(db.upcast()).krate(); | ||
1318 | Type::new(db, krate, def, ty) | ||
1319 | } | ||
1320 | |||
1321 | pub fn source(self, db: &dyn HirDatabase) -> InFile<Either<ast::IdentPat, ast::SelfParam>> { | ||
1322 | let (_body, source_map) = db.body_with_source_map(self.parent.into()); | ||
1323 | let src = source_map.pat_syntax(self.pat_id).unwrap(); // Hmm... | ||
1324 | let root = src.file_syntax(db.upcast()); | ||
1325 | src.map(|ast| { | ||
1326 | ast.map_left(|it| it.cast().unwrap().to_node(&root)).map_right(|it| it.to_node(&root)) | ||
1327 | }) | ||
1328 | } | ||
1329 | } | ||
1330 | |||
1331 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] | ||
1332 | pub struct Label { | ||
1333 | pub(crate) parent: DefWithBodyId, | ||
1334 | pub(crate) label_id: LabelId, | ||
1335 | } | ||
1336 | |||
1337 | impl Label { | ||
1338 | pub fn module(self, db: &dyn HirDatabase) -> Module { | ||
1339 | self.parent(db).module(db) | ||
1340 | } | ||
1341 | |||
1342 | pub fn parent(self, _db: &dyn HirDatabase) -> DefWithBody { | ||
1343 | self.parent.into() | ||
1344 | } | ||
1345 | |||
1346 | pub fn name(self, db: &dyn HirDatabase) -> Name { | ||
1347 | let body = db.body(self.parent.into()); | ||
1348 | body[self.label_id].name.clone() | ||
1349 | } | ||
1350 | |||
1351 | pub fn source(self, db: &dyn HirDatabase) -> InFile<ast::Label> { | ||
1352 | let (_body, source_map) = db.body_with_source_map(self.parent.into()); | ||
1353 | let src = source_map.label_syntax(self.label_id); | ||
1354 | let root = src.file_syntax(db.upcast()); | ||
1355 | src.map(|ast| ast.to_node(&root)) | ||
1356 | } | ||
1357 | } | ||
1358 | |||
1359 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] | ||
1360 | pub enum GenericParam { | ||
1361 | TypeParam(TypeParam), | ||
1362 | LifetimeParam(LifetimeParam), | ||
1363 | ConstParam(ConstParam), | ||
1364 | } | ||
1365 | impl_from!(TypeParam, LifetimeParam, ConstParam for GenericParam); | ||
1366 | |||
1367 | impl GenericParam { | ||
1368 | pub fn module(self, db: &dyn HirDatabase) -> Module { | ||
1369 | match self { | ||
1370 | GenericParam::TypeParam(it) => it.module(db), | ||
1371 | GenericParam::LifetimeParam(it) => it.module(db), | ||
1372 | GenericParam::ConstParam(it) => it.module(db), | ||
1373 | } | ||
1374 | } | ||
1375 | |||
1376 | pub fn name(self, db: &dyn HirDatabase) -> Name { | ||
1377 | match self { | ||
1378 | GenericParam::TypeParam(it) => it.name(db), | ||
1379 | GenericParam::LifetimeParam(it) => it.name(db), | ||
1380 | GenericParam::ConstParam(it) => it.name(db), | ||
1381 | } | ||
1382 | } | ||
1383 | } | ||
1384 | |||
1385 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] | ||
1386 | pub struct TypeParam { | ||
1387 | pub(crate) id: TypeParamId, | ||
1388 | } | ||
1389 | |||
1390 | impl TypeParam { | ||
1391 | pub fn name(self, db: &dyn HirDatabase) -> Name { | ||
1392 | let params = db.generic_params(self.id.parent); | ||
1393 | params.types[self.id.local_id].name.clone().unwrap_or_else(Name::missing) | ||
1394 | } | ||
1395 | |||
1396 | pub fn module(self, db: &dyn HirDatabase) -> Module { | ||
1397 | self.id.parent.module(db.upcast()).into() | ||
1398 | } | ||
1399 | |||
1400 | pub fn ty(self, db: &dyn HirDatabase) -> Type { | ||
1401 | let resolver = self.id.parent.resolver(db.upcast()); | ||
1402 | let environment = TraitEnvironment::lower(db, &resolver); | ||
1403 | let ty = Ty::Placeholder(self.id); | ||
1404 | Type { | ||
1405 | krate: self.id.parent.module(db.upcast()).krate(), | ||
1406 | ty: InEnvironment { value: ty, environment }, | ||
1407 | } | ||
1408 | } | ||
1409 | |||
1410 | pub fn trait_bounds(self, db: &dyn HirDatabase) -> Vec<Trait> { | ||
1411 | db.generic_predicates_for_param(self.id) | ||
1412 | .into_iter() | ||
1413 | .filter_map(|pred| match &pred.value { | ||
1414 | hir_ty::GenericPredicate::Implemented(trait_ref) => { | ||
1415 | Some(Trait::from(trait_ref.trait_)) | ||
1416 | } | ||
1417 | _ => None, | ||
1418 | }) | ||
1419 | .collect() | ||
1420 | } | ||
1421 | |||
1422 | pub fn default(self, db: &dyn HirDatabase) -> Option<Type> { | ||
1423 | let params = db.generic_defaults(self.id.parent); | ||
1424 | let local_idx = hir_ty::param_idx(db, self.id)?; | ||
1425 | let resolver = self.id.parent.resolver(db.upcast()); | ||
1426 | let environment = TraitEnvironment::lower(db, &resolver); | ||
1427 | let ty = params.get(local_idx)?.clone(); | ||
1428 | let subst = Substs::type_params(db, self.id.parent); | ||
1429 | let ty = ty.subst(&subst.prefix(local_idx)); | ||
1430 | Some(Type { | ||
1431 | krate: self.id.parent.module(db.upcast()).krate(), | ||
1432 | ty: InEnvironment { value: ty, environment }, | ||
1433 | }) | ||
1434 | } | ||
1435 | } | ||
1436 | |||
1437 | impl HirDisplay for TypeParam { | ||
1438 | fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> { | ||
1439 | write!(f, "{}", self.name(f.db))?; | ||
1440 | let bounds = f.db.generic_predicates_for_param(self.id); | ||
1441 | let substs = Substs::type_params(f.db, self.id.parent); | ||
1442 | let predicates = bounds.iter().cloned().map(|b| b.subst(&substs)).collect::<Vec<_>>(); | ||
1443 | if !(predicates.is_empty() || f.omit_verbose_types()) { | ||
1444 | write_bounds_like_dyn_trait_with_prefix(":", &predicates, f)?; | ||
1445 | } | ||
1446 | Ok(()) | ||
1447 | } | ||
1448 | } | ||
1449 | |||
1450 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] | ||
1451 | pub struct LifetimeParam { | ||
1452 | pub(crate) id: LifetimeParamId, | ||
1453 | } | ||
1454 | |||
1455 | impl LifetimeParam { | ||
1456 | pub fn name(self, db: &dyn HirDatabase) -> Name { | ||
1457 | let params = db.generic_params(self.id.parent); | ||
1458 | params.lifetimes[self.id.local_id].name.clone() | ||
1459 | } | ||
1460 | |||
1461 | pub fn module(self, db: &dyn HirDatabase) -> Module { | ||
1462 | self.id.parent.module(db.upcast()).into() | ||
1463 | } | ||
1464 | |||
1465 | pub fn parent(self, _db: &dyn HirDatabase) -> GenericDef { | ||
1466 | self.id.parent.into() | ||
1467 | } | ||
1468 | } | ||
1469 | |||
1470 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] | ||
1471 | pub struct ConstParam { | ||
1472 | pub(crate) id: ConstParamId, | ||
1473 | } | ||
1474 | |||
1475 | impl ConstParam { | ||
1476 | pub fn name(self, db: &dyn HirDatabase) -> Name { | ||
1477 | let params = db.generic_params(self.id.parent); | ||
1478 | params.consts[self.id.local_id].name.clone() | ||
1479 | } | ||
1480 | |||
1481 | pub fn module(self, db: &dyn HirDatabase) -> Module { | ||
1482 | self.id.parent.module(db.upcast()).into() | ||
1483 | } | ||
1484 | |||
1485 | pub fn parent(self, _db: &dyn HirDatabase) -> GenericDef { | ||
1486 | self.id.parent.into() | ||
1487 | } | ||
1488 | |||
1489 | pub fn ty(self, db: &dyn HirDatabase) -> Type { | ||
1490 | let def = self.id.parent; | ||
1491 | let krate = def.module(db.upcast()).krate(); | ||
1492 | Type::new(db, krate, def, db.const_param_ty(self.id)) | ||
1493 | } | ||
1494 | } | ||
1495 | |||
1496 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
1497 | pub struct Impl { | ||
1498 | pub(crate) id: ImplId, | ||
1499 | } | ||
1500 | |||
1501 | impl Impl { | ||
1502 | pub fn all_in_crate(db: &dyn HirDatabase, krate: Crate) -> Vec<Impl> { | ||
1503 | let inherent = db.inherent_impls_in_crate(krate.id); | ||
1504 | let trait_ = db.trait_impls_in_crate(krate.id); | ||
1505 | |||
1506 | inherent.all_impls().chain(trait_.all_impls()).map(Self::from).collect() | ||
1507 | } | ||
1508 | pub fn for_trait(db: &dyn HirDatabase, krate: Crate, trait_: Trait) -> Vec<Impl> { | ||
1509 | let impls = db.trait_impls_in_crate(krate.id); | ||
1510 | impls.for_trait(trait_.id).map(Self::from).collect() | ||
1511 | } | ||
1512 | |||
1513 | // FIXME: the return type is wrong. This should be a hir version of | ||
1514 | // `TraitRef` (ie, resolved `TypeRef`). | ||
1515 | pub fn target_trait(self, db: &dyn HirDatabase) -> Option<TypeRef> { | ||
1516 | db.impl_data(self.id).target_trait.clone() | ||
1517 | } | ||
1518 | |||
1519 | pub fn target_ty(self, db: &dyn HirDatabase) -> Type { | ||
1520 | let impl_data = db.impl_data(self.id); | ||
1521 | let resolver = self.id.resolver(db.upcast()); | ||
1522 | let ctx = hir_ty::TyLoweringContext::new(db, &resolver); | ||
1523 | let environment = TraitEnvironment::lower(db, &resolver); | ||
1524 | let ty = Ty::from_hir(&ctx, &impl_data.target_type); | ||
1525 | Type { | ||
1526 | krate: self.id.lookup(db.upcast()).container.module(db.upcast()).krate(), | ||
1527 | ty: InEnvironment { value: ty, environment }, | ||
1528 | } | ||
1529 | } | ||
1530 | |||
1531 | pub fn items(self, db: &dyn HirDatabase) -> Vec<AssocItem> { | ||
1532 | db.impl_data(self.id).items.iter().map(|it| (*it).into()).collect() | ||
1533 | } | ||
1534 | |||
1535 | pub fn is_negative(self, db: &dyn HirDatabase) -> bool { | ||
1536 | db.impl_data(self.id).is_negative | ||
1537 | } | ||
1538 | |||
1539 | pub fn module(self, db: &dyn HirDatabase) -> Module { | ||
1540 | self.id.lookup(db.upcast()).container.module(db.upcast()).into() | ||
1541 | } | ||
1542 | |||
1543 | pub fn krate(self, db: &dyn HirDatabase) -> Crate { | ||
1544 | Crate { id: self.module(db).id.krate() } | ||
1545 | } | ||
1546 | |||
1547 | pub fn is_builtin_derive(self, db: &dyn HirDatabase) -> Option<InFile<ast::Attr>> { | ||
1548 | let src = self.source(db)?; | ||
1549 | let item = src.file_id.is_builtin_derive(db.upcast())?; | ||
1550 | let hygenic = hir_expand::hygiene::Hygiene::new(db.upcast(), item.file_id); | ||
1551 | |||
1552 | // FIXME: handle `cfg_attr` | ||
1553 | let attr = item | ||
1554 | .value | ||
1555 | .attrs() | ||
1556 | .filter_map(|it| { | ||
1557 | let path = ModPath::from_src(it.path()?, &hygenic)?; | ||
1558 | if path.as_ident()?.to_string() == "derive" { | ||
1559 | Some(it) | ||
1560 | } else { | ||
1561 | None | ||
1562 | } | ||
1563 | }) | ||
1564 | .last()?; | ||
1565 | |||
1566 | Some(item.with_value(attr)) | ||
1567 | } | ||
1568 | } | ||
1569 | |||
1570 | #[derive(Clone, PartialEq, Eq, Debug)] | ||
1571 | pub struct Type { | ||
1572 | krate: CrateId, | ||
1573 | ty: InEnvironment<Ty>, | ||
1574 | } | ||
1575 | |||
1576 | impl Type { | ||
1577 | pub(crate) fn new_with_resolver( | ||
1578 | db: &dyn HirDatabase, | ||
1579 | resolver: &Resolver, | ||
1580 | ty: Ty, | ||
1581 | ) -> Option<Type> { | ||
1582 | let krate = resolver.krate()?; | ||
1583 | Some(Type::new_with_resolver_inner(db, krate, resolver, ty)) | ||
1584 | } | ||
1585 | pub(crate) fn new_with_resolver_inner( | ||
1586 | db: &dyn HirDatabase, | ||
1587 | krate: CrateId, | ||
1588 | resolver: &Resolver, | ||
1589 | ty: Ty, | ||
1590 | ) -> Type { | ||
1591 | let environment = TraitEnvironment::lower(db, &resolver); | ||
1592 | Type { krate, ty: InEnvironment { value: ty, environment } } | ||
1593 | } | ||
1594 | |||
1595 | fn new(db: &dyn HirDatabase, krate: CrateId, lexical_env: impl HasResolver, ty: Ty) -> Type { | ||
1596 | let resolver = lexical_env.resolver(db.upcast()); | ||
1597 | let environment = TraitEnvironment::lower(db, &resolver); | ||
1598 | Type { krate, ty: InEnvironment { value: ty, environment } } | ||
1599 | } | ||
1600 | |||
1601 | fn from_def( | ||
1602 | db: &dyn HirDatabase, | ||
1603 | krate: CrateId, | ||
1604 | def: impl HasResolver + Into<TyDefId> + Into<GenericDefId>, | ||
1605 | ) -> Type { | ||
1606 | let substs = Substs::build_for_def(db, def).fill_with_unknown().build(); | ||
1607 | let ty = db.ty(def.into()).subst(&substs); | ||
1608 | Type::new(db, krate, def, ty) | ||
1609 | } | ||
1610 | |||
1611 | pub fn is_unit(&self) -> bool { | ||
1612 | matches!(self.ty.value, Ty::Tuple(0, ..)) | ||
1613 | } | ||
1614 | pub fn is_bool(&self) -> bool { | ||
1615 | matches!(self.ty.value, Ty::Scalar(Scalar::Bool)) | ||
1616 | } | ||
1617 | |||
1618 | pub fn is_mutable_reference(&self) -> bool { | ||
1619 | matches!(self.ty.value, Ty::Ref(hir_ty::Mutability::Mut, ..)) | ||
1620 | } | ||
1621 | |||
1622 | pub fn remove_ref(&self) -> Option<Type> { | ||
1623 | if let Ty::Ref(.., substs) = &self.ty.value { | ||
1624 | Some(self.derived(substs[0].clone())) | ||
1625 | } else { | ||
1626 | None | ||
1627 | } | ||
1628 | } | ||
1629 | |||
1630 | pub fn is_unknown(&self) -> bool { | ||
1631 | matches!(self.ty.value, Ty::Unknown) | ||
1632 | } | ||
1633 | |||
1634 | /// Checks that particular type `ty` implements `std::future::Future`. | ||
1635 | /// This function is used in `.await` syntax completion. | ||
1636 | pub fn impls_future(&self, db: &dyn HirDatabase) -> bool { | ||
1637 | // No special case for the type of async block, since Chalk can figure it out. | ||
1638 | |||
1639 | let krate = self.krate; | ||
1640 | |||
1641 | let std_future_trait = | ||
1642 | db.lang_item(krate, "future_trait".into()).and_then(|it| it.as_trait()); | ||
1643 | let std_future_trait = match std_future_trait { | ||
1644 | Some(it) => it, | ||
1645 | None => return false, | ||
1646 | }; | ||
1647 | |||
1648 | let canonical_ty = Canonical { value: self.ty.value.clone(), kinds: Arc::new([]) }; | ||
1649 | method_resolution::implements_trait( | ||
1650 | &canonical_ty, | ||
1651 | db, | ||
1652 | self.ty.environment.clone(), | ||
1653 | krate, | ||
1654 | std_future_trait, | ||
1655 | ) | ||
1656 | } | ||
1657 | |||
1658 | /// Checks that particular type `ty` implements `std::ops::FnOnce`. | ||
1659 | /// | ||
1660 | /// This function can be used to check if a particular type is callable, since FnOnce is a | ||
1661 | /// supertrait of Fn and FnMut, so all callable types implements at least FnOnce. | ||
1662 | pub fn impls_fnonce(&self, db: &dyn HirDatabase) -> bool { | ||
1663 | let krate = self.krate; | ||
1664 | |||
1665 | let fnonce_trait = match FnTrait::FnOnce.get_id(db, krate) { | ||
1666 | Some(it) => it, | ||
1667 | None => return false, | ||
1668 | }; | ||
1669 | |||
1670 | let canonical_ty = Canonical { value: self.ty.value.clone(), kinds: Arc::new([]) }; | ||
1671 | method_resolution::implements_trait_unique( | ||
1672 | &canonical_ty, | ||
1673 | db, | ||
1674 | self.ty.environment.clone(), | ||
1675 | krate, | ||
1676 | fnonce_trait, | ||
1677 | ) | ||
1678 | } | ||
1679 | |||
1680 | pub fn impls_trait(&self, db: &dyn HirDatabase, trait_: Trait, args: &[Type]) -> bool { | ||
1681 | let trait_ref = hir_ty::TraitRef { | ||
1682 | trait_: trait_.id, | ||
1683 | substs: Substs::build_for_def(db, trait_.id) | ||
1684 | .push(self.ty.value.clone()) | ||
1685 | .fill(args.iter().map(|t| t.ty.value.clone())) | ||
1686 | .build(), | ||
1687 | }; | ||
1688 | |||
1689 | let goal = Canonical { | ||
1690 | value: hir_ty::InEnvironment::new( | ||
1691 | self.ty.environment.clone(), | ||
1692 | hir_ty::Obligation::Trait(trait_ref), | ||
1693 | ), | ||
1694 | kinds: Arc::new([]), | ||
1695 | }; | ||
1696 | |||
1697 | db.trait_solve(self.krate, goal).is_some() | ||
1698 | } | ||
1699 | |||
1700 | pub fn normalize_trait_assoc_type( | ||
1701 | &self, | ||
1702 | db: &dyn HirDatabase, | ||
1703 | trait_: Trait, | ||
1704 | args: &[Type], | ||
1705 | alias: TypeAlias, | ||
1706 | ) -> Option<Type> { | ||
1707 | let subst = Substs::build_for_def(db, trait_.id) | ||
1708 | .push(self.ty.value.clone()) | ||
1709 | .fill(args.iter().map(|t| t.ty.value.clone())) | ||
1710 | .build(); | ||
1711 | let predicate = ProjectionPredicate { | ||
1712 | projection_ty: ProjectionTy { associated_ty: alias.id, parameters: subst }, | ||
1713 | ty: Ty::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)), | ||
1714 | }; | ||
1715 | let goal = Canonical { | ||
1716 | value: InEnvironment::new( | ||
1717 | self.ty.environment.clone(), | ||
1718 | Obligation::Projection(predicate), | ||
1719 | ), | ||
1720 | kinds: Arc::new([TyVariableKind::General]), | ||
1721 | }; | ||
1722 | |||
1723 | match db.trait_solve(self.krate, goal)? { | ||
1724 | Solution::Unique(SolutionVariables(subst)) => subst.value.first().cloned(), | ||
1725 | Solution::Ambig(_) => None, | ||
1726 | } | ||
1727 | .map(|ty| Type { | ||
1728 | krate: self.krate, | ||
1729 | ty: InEnvironment { value: ty, environment: Arc::clone(&self.ty.environment) }, | ||
1730 | }) | ||
1731 | } | ||
1732 | |||
1733 | pub fn is_copy(&self, db: &dyn HirDatabase) -> bool { | ||
1734 | let lang_item = db.lang_item(self.krate, SmolStr::new("copy")); | ||
1735 | let copy_trait = match lang_item { | ||
1736 | Some(LangItemTarget::TraitId(it)) => it, | ||
1737 | _ => return false, | ||
1738 | }; | ||
1739 | self.impls_trait(db, copy_trait.into(), &[]) | ||
1740 | } | ||
1741 | |||
1742 | pub fn as_callable(&self, db: &dyn HirDatabase) -> Option<Callable> { | ||
1743 | let def = match self.ty.value { | ||
1744 | Ty::FnDef(def, _) => Some(def), | ||
1745 | _ => None, | ||
1746 | }; | ||
1747 | |||
1748 | let sig = self.ty.value.callable_sig(db)?; | ||
1749 | Some(Callable { ty: self.clone(), sig, def, is_bound_method: false }) | ||
1750 | } | ||
1751 | |||
1752 | pub fn is_closure(&self) -> bool { | ||
1753 | matches!(&self.ty.value, Ty::Closure { .. }) | ||
1754 | } | ||
1755 | |||
1756 | pub fn is_fn(&self) -> bool { | ||
1757 | matches!(&self.ty.value, Ty::FnDef(..) | Ty::Function { .. }) | ||
1758 | } | ||
1759 | |||
1760 | pub fn is_packed(&self, db: &dyn HirDatabase) -> bool { | ||
1761 | let adt_id = match self.ty.value { | ||
1762 | Ty::Adt(hir_ty::AdtId(adt_id), ..) => adt_id, | ||
1763 | _ => return false, | ||
1764 | }; | ||
1765 | |||
1766 | let adt = adt_id.into(); | ||
1767 | match adt { | ||
1768 | Adt::Struct(s) => matches!(s.repr(db), Some(ReprKind::Packed)), | ||
1769 | _ => false, | ||
1770 | } | ||
1771 | } | ||
1772 | |||
1773 | pub fn is_raw_ptr(&self) -> bool { | ||
1774 | matches!(&self.ty.value, Ty::Raw(..)) | ||
1775 | } | ||
1776 | |||
1777 | pub fn contains_unknown(&self) -> bool { | ||
1778 | return go(&self.ty.value); | ||
1779 | |||
1780 | fn go(ty: &Ty) -> bool { | ||
1781 | match ty { | ||
1782 | Ty::Unknown => true, | ||
1783 | _ => ty.substs().map_or(false, |substs| substs.iter().any(go)), | ||
1784 | } | ||
1785 | } | ||
1786 | } | ||
1787 | |||
1788 | pub fn fields(&self, db: &dyn HirDatabase) -> Vec<(Field, Type)> { | ||
1789 | let (variant_id, substs) = match self.ty.value { | ||
1790 | Ty::Adt(hir_ty::AdtId(AdtId::StructId(s)), ref substs) => (s.into(), substs), | ||
1791 | Ty::Adt(hir_ty::AdtId(AdtId::UnionId(u)), ref substs) => (u.into(), substs), | ||
1792 | _ => return Vec::new(), | ||
1793 | }; | ||
1794 | |||
1795 | db.field_types(variant_id) | ||
1796 | .iter() | ||
1797 | .map(|(local_id, ty)| { | ||
1798 | let def = Field { parent: variant_id.into(), id: local_id }; | ||
1799 | let ty = ty.clone().subst(substs); | ||
1800 | (def, self.derived(ty)) | ||
1801 | }) | ||
1802 | .collect() | ||
1803 | } | ||
1804 | |||
1805 | pub fn tuple_fields(&self, _db: &dyn HirDatabase) -> Vec<Type> { | ||
1806 | if let Ty::Tuple(_, substs) = &self.ty.value { | ||
1807 | substs.iter().map(|ty| self.derived(ty.clone())).collect() | ||
1808 | } else { | ||
1809 | Vec::new() | ||
1810 | } | ||
1811 | } | ||
1812 | |||
1813 | pub fn autoderef<'a>(&'a self, db: &'a dyn HirDatabase) -> impl Iterator<Item = Type> + 'a { | ||
1814 | // There should be no inference vars in types passed here | ||
1815 | // FIXME check that? | ||
1816 | let canonical = Canonical { value: self.ty.value.clone(), kinds: Arc::new([]) }; | ||
1817 | let environment = self.ty.environment.clone(); | ||
1818 | let ty = InEnvironment { value: canonical, environment }; | ||
1819 | autoderef(db, Some(self.krate), ty) | ||
1820 | .map(|canonical| canonical.value) | ||
1821 | .map(move |ty| self.derived(ty)) | ||
1822 | } | ||
1823 | |||
1824 | // This would be nicer if it just returned an iterator, but that runs into | ||
1825 | // lifetime problems, because we need to borrow temp `CrateImplDefs`. | ||
1826 | pub fn iterate_assoc_items<T>( | ||
1827 | self, | ||
1828 | db: &dyn HirDatabase, | ||
1829 | krate: Crate, | ||
1830 | mut callback: impl FnMut(AssocItem) -> Option<T>, | ||
1831 | ) -> Option<T> { | ||
1832 | for krate in self.ty.value.def_crates(db, krate.id)? { | ||
1833 | let impls = db.inherent_impls_in_crate(krate); | ||
1834 | |||
1835 | for impl_def in impls.for_self_ty(&self.ty.value) { | ||
1836 | for &item in db.impl_data(*impl_def).items.iter() { | ||
1837 | if let Some(result) = callback(item.into()) { | ||
1838 | return Some(result); | ||
1839 | } | ||
1840 | } | ||
1841 | } | ||
1842 | } | ||
1843 | None | ||
1844 | } | ||
1845 | |||
1846 | pub fn type_parameters(&self) -> impl Iterator<Item = Type> + '_ { | ||
1847 | self.ty | ||
1848 | .value | ||
1849 | .strip_references() | ||
1850 | .substs() | ||
1851 | .into_iter() | ||
1852 | .flat_map(|substs| substs.iter()) | ||
1853 | .map(move |ty| self.derived(ty.clone())) | ||
1854 | } | ||
1855 | |||
1856 | pub fn iterate_method_candidates<T>( | ||
1857 | &self, | ||
1858 | db: &dyn HirDatabase, | ||
1859 | krate: Crate, | ||
1860 | traits_in_scope: &FxHashSet<TraitId>, | ||
1861 | name: Option<&Name>, | ||
1862 | mut callback: impl FnMut(&Ty, Function) -> Option<T>, | ||
1863 | ) -> Option<T> { | ||
1864 | // There should be no inference vars in types passed here | ||
1865 | // FIXME check that? | ||
1866 | // FIXME replace Unknown by bound vars here | ||
1867 | let canonical = Canonical { value: self.ty.value.clone(), kinds: Arc::new([]) }; | ||
1868 | |||
1869 | let env = self.ty.environment.clone(); | ||
1870 | let krate = krate.id; | ||
1871 | |||
1872 | method_resolution::iterate_method_candidates( | ||
1873 | &canonical, | ||
1874 | db, | ||
1875 | env, | ||
1876 | krate, | ||
1877 | traits_in_scope, | ||
1878 | name, | ||
1879 | method_resolution::LookupMode::MethodCall, | ||
1880 | |ty, it| match it { | ||
1881 | AssocItemId::FunctionId(f) => callback(ty, f.into()), | ||
1882 | _ => None, | ||
1883 | }, | ||
1884 | ) | ||
1885 | } | ||
1886 | |||
1887 | pub fn iterate_path_candidates<T>( | ||
1888 | &self, | ||
1889 | db: &dyn HirDatabase, | ||
1890 | krate: Crate, | ||
1891 | traits_in_scope: &FxHashSet<TraitId>, | ||
1892 | name: Option<&Name>, | ||
1893 | mut callback: impl FnMut(&Ty, AssocItem) -> Option<T>, | ||
1894 | ) -> Option<T> { | ||
1895 | // There should be no inference vars in types passed here | ||
1896 | // FIXME check that? | ||
1897 | // FIXME replace Unknown by bound vars here | ||
1898 | let canonical = Canonical { value: self.ty.value.clone(), kinds: Arc::new([]) }; | ||
1899 | |||
1900 | let env = self.ty.environment.clone(); | ||
1901 | let krate = krate.id; | ||
1902 | |||
1903 | method_resolution::iterate_method_candidates( | ||
1904 | &canonical, | ||
1905 | db, | ||
1906 | env, | ||
1907 | krate, | ||
1908 | traits_in_scope, | ||
1909 | name, | ||
1910 | method_resolution::LookupMode::Path, | ||
1911 | |ty, it| callback(ty, it.into()), | ||
1912 | ) | ||
1913 | } | ||
1914 | |||
1915 | pub fn as_adt(&self) -> Option<Adt> { | ||
1916 | let (adt, _subst) = self.ty.value.as_adt()?; | ||
1917 | Some(adt.into()) | ||
1918 | } | ||
1919 | |||
1920 | pub fn as_dyn_trait(&self) -> Option<Trait> { | ||
1921 | self.ty.value.dyn_trait().map(Into::into) | ||
1922 | } | ||
1923 | |||
1924 | pub fn as_impl_traits(&self, db: &dyn HirDatabase) -> Option<Vec<Trait>> { | ||
1925 | self.ty.value.impl_trait_bounds(db).map(|it| { | ||
1926 | it.into_iter() | ||
1927 | .filter_map(|pred| match pred { | ||
1928 | hir_ty::GenericPredicate::Implemented(trait_ref) => { | ||
1929 | Some(Trait::from(trait_ref.trait_)) | ||
1930 | } | ||
1931 | _ => None, | ||
1932 | }) | ||
1933 | .collect() | ||
1934 | }) | ||
1935 | } | ||
1936 | |||
1937 | pub fn as_associated_type_parent_trait(&self, db: &dyn HirDatabase) -> Option<Trait> { | ||
1938 | self.ty.value.associated_type_parent_trait(db).map(Into::into) | ||
1939 | } | ||
1940 | |||
1941 | // FIXME: provide required accessors such that it becomes implementable from outside. | ||
1942 | pub fn is_equal_for_find_impls(&self, other: &Type) -> bool { | ||
1943 | let rref = other.remove_ref(); | ||
1944 | self.ty.value.equals_ctor(rref.as_ref().map_or(&other.ty.value, |it| &it.ty.value)) | ||
1945 | } | ||
1946 | |||
1947 | fn derived(&self, ty: Ty) -> Type { | ||
1948 | Type { | ||
1949 | krate: self.krate, | ||
1950 | ty: InEnvironment { value: ty, environment: self.ty.environment.clone() }, | ||
1951 | } | ||
1952 | } | ||
1953 | |||
1954 | pub fn walk(&self, db: &dyn HirDatabase, mut cb: impl FnMut(Type)) { | ||
1955 | // TypeWalk::walk for a Ty at first visits parameters and only after that the Ty itself. | ||
1956 | // We need a different order here. | ||
1957 | |||
1958 | fn walk_substs( | ||
1959 | db: &dyn HirDatabase, | ||
1960 | type_: &Type, | ||
1961 | substs: &Substs, | ||
1962 | cb: &mut impl FnMut(Type), | ||
1963 | ) { | ||
1964 | for ty in substs.iter() { | ||
1965 | walk_type(db, &type_.derived(ty.clone()), cb); | ||
1966 | } | ||
1967 | } | ||
1968 | |||
1969 | fn walk_bounds( | ||
1970 | db: &dyn HirDatabase, | ||
1971 | type_: &Type, | ||
1972 | bounds: &[GenericPredicate], | ||
1973 | cb: &mut impl FnMut(Type), | ||
1974 | ) { | ||
1975 | for pred in bounds { | ||
1976 | match pred { | ||
1977 | GenericPredicate::Implemented(trait_ref) => { | ||
1978 | cb(type_.clone()); | ||
1979 | walk_substs(db, type_, &trait_ref.substs, cb); | ||
1980 | } | ||
1981 | _ => (), | ||
1982 | } | ||
1983 | } | ||
1984 | } | ||
1985 | |||
1986 | fn walk_type(db: &dyn HirDatabase, type_: &Type, cb: &mut impl FnMut(Type)) { | ||
1987 | let ty = type_.ty.value.strip_references(); | ||
1988 | match ty { | ||
1989 | Ty::Adt(..) => { | ||
1990 | cb(type_.derived(ty.clone())); | ||
1991 | } | ||
1992 | Ty::AssociatedType(..) => { | ||
1993 | if let Some(_) = ty.associated_type_parent_trait(db) { | ||
1994 | cb(type_.derived(ty.clone())); | ||
1995 | } | ||
1996 | } | ||
1997 | Ty::OpaqueType(..) => { | ||
1998 | if let Some(bounds) = ty.impl_trait_bounds(db) { | ||
1999 | walk_bounds(db, &type_.derived(ty.clone()), &bounds, cb); | ||
2000 | } | ||
2001 | } | ||
2002 | Ty::Alias(AliasTy::Opaque(opaque_ty)) => { | ||
2003 | if let Some(bounds) = ty.impl_trait_bounds(db) { | ||
2004 | walk_bounds(db, &type_.derived(ty.clone()), &bounds, cb); | ||
2005 | } | ||
2006 | |||
2007 | walk_substs(db, type_, &opaque_ty.parameters, cb); | ||
2008 | } | ||
2009 | Ty::Placeholder(_) => { | ||
2010 | if let Some(bounds) = ty.impl_trait_bounds(db) { | ||
2011 | walk_bounds(db, &type_.derived(ty.clone()), &bounds, cb); | ||
2012 | } | ||
2013 | } | ||
2014 | Ty::Dyn(bounds) => { | ||
2015 | walk_bounds(db, &type_.derived(ty.clone()), bounds.as_ref(), cb); | ||
2016 | } | ||
2017 | |||
2018 | _ => {} | ||
2019 | } | ||
2020 | if let Some(substs) = ty.substs() { | ||
2021 | walk_substs(db, type_, &substs, cb); | ||
2022 | } | ||
2023 | } | ||
2024 | |||
2025 | walk_type(db, self, &mut cb); | ||
2026 | } | ||
2027 | } | ||
2028 | |||
2029 | impl HirDisplay for Type { | ||
2030 | fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> { | ||
2031 | self.ty.value.hir_fmt(f) | ||
2032 | } | ||
2033 | } | ||
2034 | |||
2035 | // FIXME: closures | ||
2036 | #[derive(Debug)] | ||
2037 | pub struct Callable { | ||
2038 | ty: Type, | ||
2039 | sig: CallableSig, | ||
2040 | def: Option<CallableDefId>, | ||
2041 | pub(crate) is_bound_method: bool, | ||
2042 | } | ||
2043 | |||
2044 | pub enum CallableKind { | ||
2045 | Function(Function), | ||
2046 | TupleStruct(Struct), | ||
2047 | TupleEnumVariant(Variant), | ||
2048 | Closure, | ||
2049 | } | ||
2050 | |||
2051 | impl Callable { | ||
2052 | pub fn kind(&self) -> CallableKind { | ||
2053 | match self.def { | ||
2054 | Some(CallableDefId::FunctionId(it)) => CallableKind::Function(it.into()), | ||
2055 | Some(CallableDefId::StructId(it)) => CallableKind::TupleStruct(it.into()), | ||
2056 | Some(CallableDefId::EnumVariantId(it)) => CallableKind::TupleEnumVariant(it.into()), | ||
2057 | None => CallableKind::Closure, | ||
2058 | } | ||
2059 | } | ||
2060 | pub fn receiver_param(&self, db: &dyn HirDatabase) -> Option<ast::SelfParam> { | ||
2061 | let func = match self.def { | ||
2062 | Some(CallableDefId::FunctionId(it)) if self.is_bound_method => it, | ||
2063 | _ => return None, | ||
2064 | }; | ||
2065 | let src = func.lookup(db.upcast()).source(db.upcast()); | ||
2066 | let param_list = src.value.param_list()?; | ||
2067 | param_list.self_param() | ||
2068 | } | ||
2069 | pub fn n_params(&self) -> usize { | ||
2070 | self.sig.params().len() - if self.is_bound_method { 1 } else { 0 } | ||
2071 | } | ||
2072 | pub fn params( | ||
2073 | &self, | ||
2074 | db: &dyn HirDatabase, | ||
2075 | ) -> Vec<(Option<Either<ast::SelfParam, ast::Pat>>, Type)> { | ||
2076 | let types = self | ||
2077 | .sig | ||
2078 | .params() | ||
2079 | .iter() | ||
2080 | .skip(if self.is_bound_method { 1 } else { 0 }) | ||
2081 | .map(|ty| self.ty.derived(ty.clone())); | ||
2082 | let patterns = match self.def { | ||
2083 | Some(CallableDefId::FunctionId(func)) => { | ||
2084 | let src = func.lookup(db.upcast()).source(db.upcast()); | ||
2085 | src.value.param_list().map(|param_list| { | ||
2086 | param_list | ||
2087 | .self_param() | ||
2088 | .map(|it| Some(Either::Left(it))) | ||
2089 | .filter(|_| !self.is_bound_method) | ||
2090 | .into_iter() | ||
2091 | .chain(param_list.params().map(|it| it.pat().map(Either::Right))) | ||
2092 | }) | ||
2093 | } | ||
2094 | _ => None, | ||
2095 | }; | ||
2096 | patterns.into_iter().flatten().chain(iter::repeat(None)).zip(types).collect() | ||
2097 | } | ||
2098 | pub fn return_type(&self) -> Type { | ||
2099 | self.ty.derived(self.sig.ret().clone()) | ||
2100 | } | ||
2101 | } | ||
2102 | |||
2103 | /// For IDE only | ||
2104 | #[derive(Debug, PartialEq, Eq, Hash)] | ||
2105 | pub enum ScopeDef { | ||
2106 | ModuleDef(ModuleDef), | ||
2107 | MacroDef(MacroDef), | ||
2108 | GenericParam(GenericParam), | ||
2109 | ImplSelfType(Impl), | ||
2110 | AdtSelfType(Adt), | ||
2111 | Local(Local), | ||
2112 | Unknown, | ||
2113 | } | ||
2114 | |||
2115 | impl ScopeDef { | ||
2116 | pub fn all_items(def: PerNs) -> ArrayVec<[Self; 3]> { | ||
2117 | let mut items = ArrayVec::new(); | ||
2118 | |||
2119 | match (def.take_types(), def.take_values()) { | ||
2120 | (Some(m1), None) => items.push(ScopeDef::ModuleDef(m1.into())), | ||
2121 | (None, Some(m2)) => items.push(ScopeDef::ModuleDef(m2.into())), | ||
2122 | (Some(m1), Some(m2)) => { | ||
2123 | // Some items, like unit structs and enum variants, are | ||
2124 | // returned as both a type and a value. Here we want | ||
2125 | // to de-duplicate them. | ||
2126 | if m1 != m2 { | ||
2127 | items.push(ScopeDef::ModuleDef(m1.into())); | ||
2128 | items.push(ScopeDef::ModuleDef(m2.into())); | ||
2129 | } else { | ||
2130 | items.push(ScopeDef::ModuleDef(m1.into())); | ||
2131 | } | ||
2132 | } | ||
2133 | (None, None) => {} | ||
2134 | }; | ||
2135 | |||
2136 | if let Some(macro_def_id) = def.take_macros() { | ||
2137 | items.push(ScopeDef::MacroDef(macro_def_id.into())); | ||
2138 | } | ||
2139 | |||
2140 | if items.is_empty() { | ||
2141 | items.push(ScopeDef::Unknown); | ||
2142 | } | ||
2143 | |||
2144 | items | ||
2145 | } | ||
2146 | } | ||
2147 | |||
2148 | pub trait HasVisibility { | ||
2149 | fn visibility(&self, db: &dyn HirDatabase) -> Visibility; | ||
2150 | fn is_visible_from(&self, db: &dyn HirDatabase, module: Module) -> bool { | ||
2151 | let vis = self.visibility(db); | ||
2152 | vis.is_visible_from(db.upcast(), module.id) | ||
2153 | } | ||
2154 | } | ||