1 //! Helper functions for working with def, which don't need to be a separate
2 //! query, but can't be computed directly from `*Data` (ie, which need a `db`).
3
4 use std::{hash::Hash, iter};
5
6 use base_db::CrateId;
7 use chalk_ir::{
8 cast::Cast,
9 fold::{FallibleTypeFolder, Shift},
10 BoundVar, DebruijnIndex,
11 };
12 use either::Either;
13 use hir_def::{
14 db::DefDatabase,
15 generics::{
16 GenericParams, TypeOrConstParamData, TypeParamProvenance, WherePredicate,
17 WherePredicateTypeTarget,
18 },
19 lang_item::LangItem,
20 resolver::{HasResolver, TypeNs},
21 type_ref::{TraitBoundModifier, TypeRef},
22 ConstParamId, EnumId, EnumVariantId, FunctionId, GenericDefId, ItemContainerId,
23 LocalEnumVariantId, Lookup, OpaqueInternableThing, TraitId, TypeAliasId, TypeOrConstParamId,
24 TypeParamId,
25 };
26 use hir_expand::name::Name;
27 use intern::Interned;
28 use rustc_hash::FxHashSet;
29 use smallvec::{smallvec, SmallVec};
30 use stdx::never;
31
32 use crate::{
33 consteval::unknown_const,
34 db::HirDatabase,
35 layout::{Layout, TagEncoding},
36 mir::pad16,
37 ChalkTraitId, Const, ConstScalar, GenericArg, Interner, Substitution, TraitRef, TraitRefExt,
38 Ty, WhereClause,
39 };
40
fn_traits( db: &dyn DefDatabase, krate: CrateId, ) -> impl Iterator<Item = TraitId> + '_41 pub(crate) fn fn_traits(
42 db: &dyn DefDatabase,
43 krate: CrateId,
44 ) -> impl Iterator<Item = TraitId> + '_ {
45 [LangItem::Fn, LangItem::FnMut, LangItem::FnOnce]
46 .into_iter()
47 .filter_map(move |lang| db.lang_item(krate, lang))
48 .flat_map(|it| it.as_trait())
49 }
50
51 /// Returns an iterator over the whole super trait hierarchy (including the
52 /// trait itself).
all_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> SmallVec<[TraitId; 4]>53 pub fn all_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> SmallVec<[TraitId; 4]> {
54 // we need to take care a bit here to avoid infinite loops in case of cycles
55 // (i.e. if we have `trait A: B; trait B: A;`)
56
57 let mut result = smallvec![trait_];
58 let mut i = 0;
59 while let Some(&t) = result.get(i) {
60 // yeah this is quadratic, but trait hierarchies should be flat
61 // enough that this doesn't matter
62 direct_super_traits(db, t, |tt| {
63 if !result.contains(&tt) {
64 result.push(tt);
65 }
66 });
67 i += 1;
68 }
69 result
70 }
71
72 /// Given a trait ref (`Self: Trait`), builds all the implied trait refs for
73 /// super traits. The original trait ref will be included. So the difference to
74 /// `all_super_traits` is that we keep track of type parameters; for example if
75 /// we have `Self: Trait<u32, i32>` and `Trait<T, U>: OtherTrait<U>` we'll get
76 /// `Self: OtherTrait<i32>`.
all_super_trait_refs<T>( db: &dyn HirDatabase, trait_ref: TraitRef, cb: impl FnMut(TraitRef) -> Option<T>, ) -> Option<T>77 pub(super) fn all_super_trait_refs<T>(
78 db: &dyn HirDatabase,
79 trait_ref: TraitRef,
80 cb: impl FnMut(TraitRef) -> Option<T>,
81 ) -> Option<T> {
82 let seen = iter::once(trait_ref.trait_id).collect();
83 SuperTraits { db, seen, stack: vec![trait_ref] }.find_map(cb)
84 }
85
86 struct SuperTraits<'a> {
87 db: &'a dyn HirDatabase,
88 stack: Vec<TraitRef>,
89 seen: FxHashSet<ChalkTraitId>,
90 }
91
92 impl<'a> SuperTraits<'a> {
elaborate(&mut self, trait_ref: &TraitRef)93 fn elaborate(&mut self, trait_ref: &TraitRef) {
94 direct_super_trait_refs(self.db, trait_ref, |trait_ref| {
95 if !self.seen.contains(&trait_ref.trait_id) {
96 self.stack.push(trait_ref);
97 }
98 });
99 }
100 }
101
102 impl<'a> Iterator for SuperTraits<'a> {
103 type Item = TraitRef;
104
next(&mut self) -> Option<Self::Item>105 fn next(&mut self) -> Option<Self::Item> {
106 if let Some(next) = self.stack.pop() {
107 self.elaborate(&next);
108 Some(next)
109 } else {
110 None
111 }
112 }
113 }
114
direct_super_traits(db: &dyn DefDatabase, trait_: TraitId, cb: impl FnMut(TraitId))115 fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId, cb: impl FnMut(TraitId)) {
116 let resolver = trait_.resolver(db);
117 let generic_params = db.generic_params(trait_.into());
118 let trait_self = generic_params.find_trait_self_param();
119 generic_params
120 .where_predicates
121 .iter()
122 .filter_map(|pred| match pred {
123 WherePredicate::ForLifetime { target, bound, .. }
124 | WherePredicate::TypeBound { target, bound } => {
125 let is_trait = match target {
126 WherePredicateTypeTarget::TypeRef(type_ref) => match &**type_ref {
127 TypeRef::Path(p) => p.is_self_type(),
128 _ => false,
129 },
130 WherePredicateTypeTarget::TypeOrConstParam(local_id) => {
131 Some(*local_id) == trait_self
132 }
133 };
134 match is_trait {
135 true => bound.as_path(),
136 false => None,
137 }
138 }
139 WherePredicate::Lifetime { .. } => None,
140 })
141 .filter(|(_, bound_modifier)| matches!(bound_modifier, TraitBoundModifier::None))
142 .filter_map(|(path, _)| match resolver.resolve_path_in_type_ns_fully(db, path) {
143 Some(TypeNs::TraitId(t)) => Some(t),
144 _ => None,
145 })
146 .for_each(cb);
147 }
148
direct_super_trait_refs(db: &dyn HirDatabase, trait_ref: &TraitRef, cb: impl FnMut(TraitRef))149 fn direct_super_trait_refs(db: &dyn HirDatabase, trait_ref: &TraitRef, cb: impl FnMut(TraitRef)) {
150 let generic_params = db.generic_params(trait_ref.hir_trait_id().into());
151 let trait_self = match generic_params.find_trait_self_param() {
152 Some(p) => TypeOrConstParamId { parent: trait_ref.hir_trait_id().into(), local_id: p },
153 None => return,
154 };
155 db.generic_predicates_for_param(trait_self.parent, trait_self, None)
156 .iter()
157 .filter_map(|pred| {
158 pred.as_ref().filter_map(|pred| match pred.skip_binders() {
159 // FIXME: how to correctly handle higher-ranked bounds here?
160 WhereClause::Implemented(tr) => Some(
161 tr.clone()
162 .shifted_out_to(Interner, DebruijnIndex::ONE)
163 .expect("FIXME unexpected higher-ranked trait bound"),
164 ),
165 _ => None,
166 })
167 })
168 .map(|pred| pred.substitute(Interner, &trait_ref.substitution))
169 .for_each(cb);
170 }
171
associated_type_by_name_including_super_traits( db: &dyn HirDatabase, trait_ref: TraitRef, name: &Name, ) -> Option<(TraitRef, TypeAliasId)>172 pub(super) fn associated_type_by_name_including_super_traits(
173 db: &dyn HirDatabase,
174 trait_ref: TraitRef,
175 name: &Name,
176 ) -> Option<(TraitRef, TypeAliasId)> {
177 all_super_trait_refs(db, trait_ref, |t| {
178 let assoc_type = db.trait_data(t.hir_trait_id()).associated_type_by_name(name)?;
179 Some((t, assoc_type))
180 })
181 }
182
generics(db: &dyn DefDatabase, def: GenericDefId) -> Generics183 pub(crate) fn generics(db: &dyn DefDatabase, def: GenericDefId) -> Generics {
184 let parent_generics = parent_generic_def(db, def).map(|def| Box::new(generics(db, def)));
185 Generics { def, params: db.generic_params(def), parent_generics }
186 }
187
188 /// It is a bit different from the rustc equivalent. Currently it stores:
189 /// - 0: the function signature, encoded as a function pointer type
190 /// - 1..n: generics of the parent
191 ///
192 /// and it doesn't store the closure types and fields.
193 ///
194 /// Codes should not assume this ordering, and should always use methods available
195 /// on this struct for retriving, and `TyBuilder::substs_for_closure` for creating.
196 pub(crate) struct ClosureSubst<'a>(pub(crate) &'a Substitution);
197
198 impl<'a> ClosureSubst<'a> {
parent_subst(&self) -> &'a [GenericArg]199 pub(crate) fn parent_subst(&self) -> &'a [GenericArg] {
200 match self.0.as_slice(Interner) {
201 [_, x @ ..] => x,
202 _ => {
203 never!("Closure missing parameter");
204 &[]
205 }
206 }
207 }
208
sig_ty(&self) -> &'a Ty209 pub(crate) fn sig_ty(&self) -> &'a Ty {
210 match self.0.as_slice(Interner) {
211 [x, ..] => x.assert_ty_ref(Interner),
212 _ => {
213 unreachable!("Closure missing sig_ty parameter");
214 }
215 }
216 }
217 }
218
219 #[derive(Debug)]
220 pub(crate) struct Generics {
221 def: GenericDefId,
222 pub(crate) params: Interned<GenericParams>,
223 parent_generics: Option<Box<Generics>>,
224 }
225
226 impl Generics {
iter_id(&self) -> impl Iterator<Item = Either<TypeParamId, ConstParamId>> + '_227 pub(crate) fn iter_id(&self) -> impl Iterator<Item = Either<TypeParamId, ConstParamId>> + '_ {
228 self.iter().map(|(id, data)| match data {
229 TypeOrConstParamData::TypeParamData(_) => Either::Left(TypeParamId::from_unchecked(id)),
230 TypeOrConstParamData::ConstParamData(_) => {
231 Either::Right(ConstParamId::from_unchecked(id))
232 }
233 })
234 }
235
236 /// Iterator over types and const params of self, then parent.
iter<'a>( &'a self, ) -> impl DoubleEndedIterator<Item = (TypeOrConstParamId, &'a TypeOrConstParamData)> + 'a237 pub(crate) fn iter<'a>(
238 &'a self,
239 ) -> impl DoubleEndedIterator<Item = (TypeOrConstParamId, &'a TypeOrConstParamData)> + 'a {
240 let to_toc_id = |it: &'a Generics| {
241 move |(local_id, p)| (TypeOrConstParamId { parent: it.def, local_id }, p)
242 };
243 self.params.iter().map(to_toc_id(self)).chain(self.iter_parent())
244 }
245
246 /// Iterate over types and const params without parent params.
iter_self<'a>( &'a self, ) -> impl DoubleEndedIterator<Item = (TypeOrConstParamId, &'a TypeOrConstParamData)> + 'a247 pub(crate) fn iter_self<'a>(
248 &'a self,
249 ) -> impl DoubleEndedIterator<Item = (TypeOrConstParamId, &'a TypeOrConstParamData)> + 'a {
250 let to_toc_id = |it: &'a Generics| {
251 move |(local_id, p)| (TypeOrConstParamId { parent: it.def, local_id }, p)
252 };
253 self.params.iter().map(to_toc_id(self))
254 }
255
256 /// Iterator over types and const params of parent.
iter_parent( &self, ) -> impl DoubleEndedIterator<Item = (TypeOrConstParamId, &TypeOrConstParamData)>257 pub(crate) fn iter_parent(
258 &self,
259 ) -> impl DoubleEndedIterator<Item = (TypeOrConstParamId, &TypeOrConstParamData)> {
260 self.parent_generics().into_iter().flat_map(|it| {
261 let to_toc_id =
262 move |(local_id, p)| (TypeOrConstParamId { parent: it.def, local_id }, p);
263 it.params.iter().map(to_toc_id)
264 })
265 }
266
267 /// Returns total number of generic parameters in scope, including those from parent.
len(&self) -> usize268 pub(crate) fn len(&self) -> usize {
269 let parent = self.parent_generics().map_or(0, Generics::len);
270 let child = self.params.type_or_consts.len();
271 parent + child
272 }
273
274 /// Returns numbers of generic parameters excluding those from parent.
len_self(&self) -> usize275 pub(crate) fn len_self(&self) -> usize {
276 self.params.type_or_consts.len()
277 }
278
279 /// (parent total, self param, type param list, const param list, impl trait)
provenance_split(&self) -> (usize, usize, usize, usize, usize)280 pub(crate) fn provenance_split(&self) -> (usize, usize, usize, usize, usize) {
281 let mut self_params = 0;
282 let mut type_params = 0;
283 let mut impl_trait_params = 0;
284 let mut const_params = 0;
285 self.params.iter().for_each(|(_, data)| match data {
286 TypeOrConstParamData::TypeParamData(p) => match p.provenance {
287 TypeParamProvenance::TypeParamList => type_params += 1,
288 TypeParamProvenance::TraitSelf => self_params += 1,
289 TypeParamProvenance::ArgumentImplTrait => impl_trait_params += 1,
290 },
291 TypeOrConstParamData::ConstParamData(_) => const_params += 1,
292 });
293
294 let parent_len = self.parent_generics().map_or(0, Generics::len);
295 (parent_len, self_params, type_params, const_params, impl_trait_params)
296 }
297
param_idx(&self, param: TypeOrConstParamId) -> Option<usize>298 pub(crate) fn param_idx(&self, param: TypeOrConstParamId) -> Option<usize> {
299 Some(self.find_param(param)?.0)
300 }
301
find_param(&self, param: TypeOrConstParamId) -> Option<(usize, &TypeOrConstParamData)>302 fn find_param(&self, param: TypeOrConstParamId) -> Option<(usize, &TypeOrConstParamData)> {
303 if param.parent == self.def {
304 let (idx, (_local_id, data)) =
305 self.params.iter().enumerate().find(|(_, (idx, _))| *idx == param.local_id)?;
306 Some((idx, data))
307 } else {
308 self.parent_generics()
309 .and_then(|g| g.find_param(param))
310 // Remember that parent parameters come after parameters for self.
311 .map(|(idx, data)| (self.len_self() + idx, data))
312 }
313 }
314
parent_generics(&self) -> Option<&Generics>315 pub(crate) fn parent_generics(&self) -> Option<&Generics> {
316 self.parent_generics.as_deref()
317 }
318
319 /// Returns a Substitution that replaces each parameter by a bound variable.
bound_vars_subst( &self, db: &dyn HirDatabase, debruijn: DebruijnIndex, ) -> Substitution320 pub(crate) fn bound_vars_subst(
321 &self,
322 db: &dyn HirDatabase,
323 debruijn: DebruijnIndex,
324 ) -> Substitution {
325 Substitution::from_iter(
326 Interner,
327 self.iter_id().enumerate().map(|(idx, id)| match id {
328 Either::Left(_) => BoundVar::new(debruijn, idx).to_ty(Interner).cast(Interner),
329 Either::Right(id) => BoundVar::new(debruijn, idx)
330 .to_const(Interner, db.const_param_ty(id))
331 .cast(Interner),
332 }),
333 )
334 }
335
336 /// Returns a Substitution that replaces each parameter by itself (i.e. `Ty::Param`).
placeholder_subst(&self, db: &dyn HirDatabase) -> Substitution337 pub(crate) fn placeholder_subst(&self, db: &dyn HirDatabase) -> Substitution {
338 Substitution::from_iter(
339 Interner,
340 self.iter_id().map(|id| match id {
341 Either::Left(id) => {
342 crate::to_placeholder_idx(db, id.into()).to_ty(Interner).cast(Interner)
343 }
344 Either::Right(id) => crate::to_placeholder_idx(db, id.into())
345 .to_const(Interner, db.const_param_ty(id))
346 .cast(Interner),
347 }),
348 )
349 }
350 }
351
parent_generic_def(db: &dyn DefDatabase, def: GenericDefId) -> Option<GenericDefId>352 fn parent_generic_def(db: &dyn DefDatabase, def: GenericDefId) -> Option<GenericDefId> {
353 let container = match def {
354 GenericDefId::FunctionId(it) => it.lookup(db).container,
355 GenericDefId::TypeAliasId(it) => it.lookup(db).container,
356 GenericDefId::ConstId(it) => it.lookup(db).container,
357 GenericDefId::EnumVariantId(it) => return Some(it.parent.into()),
358 GenericDefId::AdtId(_)
359 | GenericDefId::TraitId(_)
360 | GenericDefId::ImplId(_)
361 | GenericDefId::TraitAliasId(_) => return None,
362 };
363
364 match container {
365 ItemContainerId::ImplId(it) => Some(it.into()),
366 ItemContainerId::TraitId(it) => Some(it.into()),
367 ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => None,
368 }
369 }
370
is_fn_unsafe_to_call(db: &dyn HirDatabase, func: FunctionId) -> bool371 pub fn is_fn_unsafe_to_call(db: &dyn HirDatabase, func: FunctionId) -> bool {
372 let data = db.function_data(func);
373 if data.has_unsafe_kw() {
374 return true;
375 }
376
377 match func.lookup(db.upcast()).container {
378 hir_def::ItemContainerId::ExternBlockId(block) => {
379 // Function in an `extern` block are always unsafe to call, except when it has
380 // `"rust-intrinsic"` ABI there are a few exceptions.
381 let id = block.lookup(db.upcast()).id;
382
383 let is_intrinsic =
384 id.item_tree(db.upcast())[id.value].abi.as_deref() == Some("rust-intrinsic");
385
386 if is_intrinsic {
387 // Intrinsics are unsafe unless they have the rustc_safe_intrinsic attribute
388 !data.attrs.by_key("rustc_safe_intrinsic").exists()
389 } else {
390 // Extern items are always unsafe
391 true
392 }
393 }
394 _ => false,
395 }
396 }
397
398 pub(crate) struct UnevaluatedConstEvaluatorFolder<'a> {
399 pub(crate) db: &'a dyn HirDatabase,
400 }
401
402 impl FallibleTypeFolder<Interner> for UnevaluatedConstEvaluatorFolder<'_> {
403 type Error = ();
404
as_dyn(&mut self) -> &mut dyn FallibleTypeFolder<Interner, Error = ()>405 fn as_dyn(&mut self) -> &mut dyn FallibleTypeFolder<Interner, Error = ()> {
406 self
407 }
408
interner(&self) -> Interner409 fn interner(&self) -> Interner {
410 Interner
411 }
412
try_fold_const( &mut self, constant: Const, _outer_binder: DebruijnIndex, ) -> Result<Const, Self::Error>413 fn try_fold_const(
414 &mut self,
415 constant: Const,
416 _outer_binder: DebruijnIndex,
417 ) -> Result<Const, Self::Error> {
418 if let chalk_ir::ConstValue::Concrete(c) = &constant.data(Interner).value {
419 if let ConstScalar::UnevaluatedConst(id, subst) = &c.interned {
420 if let Ok(eval) = self.db.const_eval(*id, subst.clone()) {
421 return Ok(eval);
422 } else {
423 return Ok(unknown_const(constant.data(Interner).ty.clone()));
424 }
425 }
426 }
427 Ok(constant)
428 }
429 }
430
detect_variant_from_bytes<'a>( layout: &'a Layout, db: &dyn HirDatabase, krate: CrateId, b: &[u8], e: EnumId, ) -> Option<(LocalEnumVariantId, &'a Layout)>431 pub(crate) fn detect_variant_from_bytes<'a>(
432 layout: &'a Layout,
433 db: &dyn HirDatabase,
434 krate: CrateId,
435 b: &[u8],
436 e: EnumId,
437 ) -> Option<(LocalEnumVariantId, &'a Layout)> {
438 let (var_id, var_layout) = match &layout.variants {
439 hir_def::layout::Variants::Single { index } => (index.0, &*layout),
440 hir_def::layout::Variants::Multiple { tag, tag_encoding, variants, .. } => {
441 let target_data_layout = db.target_data_layout(krate)?;
442 let size = tag.size(&*target_data_layout).bytes_usize();
443 let offset = layout.fields.offset(0).bytes_usize(); // The only field on enum variants is the tag field
444 let tag = i128::from_le_bytes(pad16(&b[offset..offset + size], false));
445 match tag_encoding {
446 TagEncoding::Direct => {
447 let x = variants.iter_enumerated().find(|x| {
448 db.const_eval_discriminant(EnumVariantId { parent: e, local_id: x.0 .0 })
449 == Ok(tag)
450 })?;
451 (x.0 .0, x.1)
452 }
453 TagEncoding::Niche { untagged_variant, niche_start, .. } => {
454 let candidate_tag = tag.wrapping_sub(*niche_start as i128) as usize;
455 let variant = variants
456 .iter_enumerated()
457 .map(|(x, _)| x)
458 .filter(|x| x != untagged_variant)
459 .nth(candidate_tag)
460 .unwrap_or(*untagged_variant);
461 (variant.0, &variants[variant])
462 }
463 }
464 }
465 };
466 Some((var_id, var_layout))
467 }
468
469 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
470 pub(crate) struct InTypeConstIdMetadata(pub(crate) Ty);
471
472 impl OpaqueInternableThing for InTypeConstIdMetadata {
dyn_hash(&self, mut state: &mut dyn std::hash::Hasher)473 fn dyn_hash(&self, mut state: &mut dyn std::hash::Hasher) {
474 self.hash(&mut state);
475 }
476
dyn_eq(&self, other: &dyn OpaqueInternableThing) -> bool477 fn dyn_eq(&self, other: &dyn OpaqueInternableThing) -> bool {
478 other.as_any().downcast_ref::<Self>().map_or(false, |x| self == x)
479 }
480
dyn_clone(&self) -> Box<dyn OpaqueInternableThing>481 fn dyn_clone(&self) -> Box<dyn OpaqueInternableThing> {
482 Box::new(self.clone())
483 }
484
as_any(&self) -> &dyn std::any::Any485 fn as_any(&self) -> &dyn std::any::Any {
486 self
487 }
488
box_any(&self) -> Box<dyn std::any::Any>489 fn box_any(&self) -> Box<dyn std::any::Any> {
490 Box::new(self.clone())
491 }
492 }
493