Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-ty/src/utils.rs')
-rw-r--r--crates/hir-ty/src/utils.rs200
1 files changed, 31 insertions, 169 deletions
diff --git a/crates/hir-ty/src/utils.rs b/crates/hir-ty/src/utils.rs
index 427c4bb684..7dd73f1e7a 100644
--- a/crates/hir-ty/src/utils.rs
+++ b/crates/hir-ty/src/utils.rs
@@ -1,48 +1,52 @@
//! Helper functions for working with def, which don't need to be a separate
//! query, but can't be computed directly from `*Data` (ie, which need a `db`).
-use std::{cell::LazyCell, iter};
+use std::cell::LazyCell;
-use base_db::{
- Crate,
- target::{self, TargetData},
-};
-use chalk_ir::{DebruijnIndex, fold::FallibleTypeFolder};
+use base_db::target::{self, TargetData};
use hir_def::{
- EnumId, EnumVariantId, FunctionId, Lookup, TraitId, TypeAliasId, TypeOrConstParamId,
+ EnumId, EnumVariantId, FunctionId, Lookup, TraitId,
+ attrs::AttrFlags,
db::DefDatabase,
hir::generics::WherePredicate,
- lang_item::LangItem,
+ lang_item::LangItems,
resolver::{HasResolver, TypeNs},
type_ref::{TraitBoundModifier, TypeRef},
};
-use hir_expand::name::Name;
use intern::sym;
use rustc_abi::TargetDataLayout;
-use rustc_hash::FxHashSet;
-use rustc_type_ir::inherent::{GenericArgs, IntoKind, SliceLike};
use smallvec::{SmallVec, smallvec};
use span::Edition;
-use crate::next_solver::mapping::NextSolverToChalk;
use crate::{
- ChalkTraitId, Const, ConstScalar, Interner, Substitution, TargetFeatures, TraitRef,
- TraitRefExt, Ty,
- consteval::unknown_const,
+ TargetFeatures,
db::HirDatabase,
layout::{Layout, TagEncoding},
mir::pad16,
- next_solver::{
- DbInterner,
- mapping::{ChalkToNextSolver, convert_args_for_result},
- },
- to_chalk_trait_id,
};
-pub(crate) fn fn_traits(db: &dyn DefDatabase, krate: Crate) -> impl Iterator<Item = TraitId> + '_ {
- [LangItem::Fn, LangItem::FnMut, LangItem::FnOnce]
- .into_iter()
- .filter_map(move |lang| lang.resolve_trait(db, krate))
+/// SAFETY: `old_pointer` must be valid for unique writes
+pub(crate) unsafe fn unsafe_update_eq<T>(old_pointer: *mut T, new_value: T) -> bool
+where
+ T: PartialEq,
+{
+ // SAFETY: Caller obligation
+ let old_ref: &mut T = unsafe { &mut *old_pointer };
+
+ if *old_ref != new_value {
+ *old_ref = new_value;
+ true
+ } else {
+ // Subtle but important: Eq impls can be buggy or define equality
+ // in surprising ways. If it says that the value has not changed,
+ // we do not modify the existing value, and thus do not have to
+ // update the revision, as downstream code will not see the new value.
+ false
+ }
+}
+
+pub(crate) fn fn_traits(lang_items: &LangItems) -> impl Iterator<Item = TraitId> + '_ {
+ [lang_items.Fn, lang_items.FnMut, lang_items.FnOnce].into_iter().flatten()
}
/// Returns an iterator over the direct super traits (including the trait itself).
@@ -77,49 +81,6 @@ pub fn all_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> SmallVec<[Trai
result
}
-/// Given a trait ref (`Self: Trait`), builds all the implied trait refs for
-/// super traits. The original trait ref will be included. So the difference to
-/// `all_super_traits` is that we keep track of type parameters; for example if
-/// we have `Self: Trait<u32, i32>` and `Trait<T, U>: OtherTrait<U>` we'll get
-/// `Self: OtherTrait<i32>`.
-pub(super) fn all_super_trait_refs<T>(
- db: &dyn HirDatabase,
- trait_ref: TraitRef,
- cb: impl FnMut(TraitRef) -> Option<T>,
-) -> Option<T> {
- let seen = iter::once(trait_ref.trait_id).collect();
- SuperTraits { db, seen, stack: vec![trait_ref] }.find_map(cb)
-}
-
-struct SuperTraits<'a> {
- db: &'a dyn HirDatabase,
- stack: Vec<TraitRef>,
- seen: FxHashSet<ChalkTraitId>,
-}
-
-impl SuperTraits<'_> {
- fn elaborate(&mut self, trait_ref: &TraitRef) {
- direct_super_trait_refs(self.db, trait_ref, |trait_ref| {
- if !self.seen.contains(&trait_ref.trait_id) {
- self.stack.push(trait_ref);
- }
- });
- }
-}
-
-impl Iterator for SuperTraits<'_> {
- type Item = TraitRef;
-
- fn next(&mut self) -> Option<Self::Item> {
- if let Some(next) = self.stack.pop() {
- self.elaborate(&next);
- Some(next)
- } else {
- None
- }
- }
-}
-
fn direct_super_traits_cb(db: &dyn DefDatabase, trait_: TraitId, cb: impl FnMut(TraitId)) {
let resolver = LazyCell::new(|| trait_.resolver(db));
let (generic_params, store) = db.generic_params_and_store(trait_.into());
@@ -150,71 +111,6 @@ fn direct_super_traits_cb(db: &dyn DefDatabase, trait_: TraitId, cb: impl FnMut(
.for_each(cb);
}
-fn direct_super_trait_refs(db: &dyn HirDatabase, trait_ref: &TraitRef, cb: impl FnMut(TraitRef)) {
- let interner = DbInterner::new_with(db, None, None);
- let generic_params = db.generic_params(trait_ref.hir_trait_id().into());
- let trait_self = match generic_params.trait_self_param() {
- Some(p) => TypeOrConstParamId { parent: trait_ref.hir_trait_id().into(), local_id: p },
- None => return,
- };
- let trait_ref_args: crate::next_solver::GenericArgs<'_> =
- trait_ref.substitution.to_nextsolver(interner);
- db.generic_predicates_for_param_ns(trait_self.parent, trait_self, None)
- .iter()
- .filter_map(|pred| {
- let pred = pred.kind();
- // FIXME: how to correctly handle higher-ranked bounds here?
- let pred = pred.no_bound_vars().expect("FIXME unexpected higher-ranked trait bound");
- match pred {
- rustc_type_ir::ClauseKind::Trait(t) => {
- let t =
- rustc_type_ir::EarlyBinder::bind(t).instantiate(interner, trait_ref_args);
- let trait_id = to_chalk_trait_id(t.def_id().0);
-
- let substitution =
- convert_args_for_result(interner, t.trait_ref.args.as_slice());
- let tr = chalk_ir::TraitRef { trait_id, substitution };
- Some(tr)
- }
- _ => None,
- }
- })
- .for_each(cb);
-}
-
-pub(super) fn associated_type_by_name_including_super_traits(
- db: &dyn HirDatabase,
- trait_ref: TraitRef,
- name: &Name,
-) -> Option<(TraitRef, TypeAliasId)> {
- all_super_trait_refs(db, trait_ref, |t| {
- let assoc_type = t.hir_trait_id().trait_items(db).associated_type_by_name(name)?;
- Some((t, assoc_type))
- })
-}
-
-pub(crate) struct ClosureSubst<'a>(pub(crate) &'a Substitution);
-
-impl<'a> ClosureSubst<'a> {
- pub(crate) fn parent_subst(&self, db: &dyn HirDatabase) -> Substitution {
- let interner = DbInterner::new_with(db, None, None);
- let subst =
- <Substitution as ChalkToNextSolver<crate::next_solver::GenericArgs<'_>>>::to_nextsolver(
- self.0, interner,
- );
- subst.split_closure_args().parent_args.to_chalk(interner)
- }
-
- pub(crate) fn sig_ty(&self, db: &dyn HirDatabase) -> Ty {
- let interner = DbInterner::new_with(db, None, None);
- let subst =
- <Substitution as ChalkToNextSolver<crate::next_solver::GenericArgs<'_>>>::to_nextsolver(
- self.0, interner,
- );
- subst.split_closure_args_untupled().closure_sig_as_fn_ptr_ty.to_chalk(interner)
- }
-}
-
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Unsafety {
Safe,
@@ -239,7 +135,7 @@ pub fn target_feature_is_safe_in_target(target: &TargetData) -> TargetFeatureIsS
pub fn is_fn_unsafe_to_call(
db: &dyn HirDatabase,
func: FunctionId,
- caller_target_features: &TargetFeatures,
+ caller_target_features: &TargetFeatures<'_>,
call_edition: Edition,
target_feature_is_safe: TargetFeatureIsSafeInTarget,
) -> Unsafety {
@@ -250,8 +146,7 @@ pub fn is_fn_unsafe_to_call(
if data.has_target_feature() && target_feature_is_safe == TargetFeatureIsSafeInTarget::No {
// RFC 2396 <https://rust-lang.github.io/rfcs/2396-target-feature-1.1.html>.
- let callee_target_features =
- TargetFeatures::from_attrs_no_implications(&db.attrs(func.into()));
+ let callee_target_features = TargetFeatures::from_fn_no_implications(db, func);
if !caller_target_features.enabled.is_superset(&callee_target_features.enabled) {
return Unsafety::Unsafe;
}
@@ -272,7 +167,7 @@ pub fn is_fn_unsafe_to_call(
if is_intrinsic_block {
// legacy intrinsics
// extern "rust-intrinsic" intrinsics are unsafe unless they have the rustc_safe_intrinsic attribute
- if db.attrs(func.into()).by_key(sym::rustc_safe_intrinsic).exists() {
+ if AttrFlags::query(db, func.into()).contains(AttrFlags::RUSTC_SAFE_INTRINSIC) {
Unsafety::Safe
} else {
Unsafety::Unsafe
@@ -287,39 +182,6 @@ pub fn is_fn_unsafe_to_call(
}
}
-pub(crate) struct UnevaluatedConstEvaluatorFolder<'a> {
- pub(crate) db: &'a dyn HirDatabase,
-}
-
-impl FallibleTypeFolder<Interner> for UnevaluatedConstEvaluatorFolder<'_> {
- type Error = ();
-
- fn as_dyn(&mut self) -> &mut dyn FallibleTypeFolder<Interner, Error = ()> {
- self
- }
-
- fn interner(&self) -> Interner {
- Interner
- }
-
- fn try_fold_const(
- &mut self,
- constant: Const,
- _outer_binder: DebruijnIndex,
- ) -> Result<Const, Self::Error> {
- if let chalk_ir::ConstValue::Concrete(c) = &constant.data(Interner).value
- && let ConstScalar::UnevaluatedConst(id, subst) = &c.interned
- {
- if let Ok(eval) = self.db.const_eval(*id, subst.clone(), None) {
- return Ok(eval);
- } else {
- return Ok(unknown_const(constant.data(Interner).ty.clone()));
- }
- }
- Ok(constant)
- }
-}
-
pub(crate) fn detect_variant_from_bytes<'a>(
layout: &'a Layout,
db: &dyn HirDatabase,