• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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