Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir/src/lib.rs')
-rw-r--r--crates/hir/src/lib.rs230
1 files changed, 202 insertions, 28 deletions
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index dfc91c7343..00b4db5437 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -43,7 +43,7 @@ use base_db::{CrateDisplayName, CrateId, CrateOrigin};
use either::Either;
use hir_def::{
body::BodyDiagnostic,
- data::adt::VariantData,
+ data::{adt::VariantData, TraitFlags},
generics::{LifetimeParamData, TypeOrConstParamData, TypeParamProvenance},
hir::{BindingAnnotation, BindingId, ExprId, ExprOrPatId, LabelId, Pat},
item_tree::{AttrOwner, FieldParent, ItemTreeFieldId, ItemTreeNode},
@@ -101,7 +101,6 @@ pub use crate::{
PathResolution, Semantics, SemanticsImpl, SemanticsScope, TypeInfo, VisibleTraits,
},
};
-pub use hir_ty::method_resolution::TyFingerprint;
// Be careful with these re-exports.
//
@@ -151,8 +150,9 @@ pub use {
display::{ClosureStyle, HirDisplay, HirDisplayError, HirWrite},
dyn_compatibility::{DynCompatibilityViolation, MethodViolationCode},
layout::LayoutError,
+ method_resolution::TyFingerprint,
mir::{MirEvalError, MirLowerError},
- CastError, FnAbi, PointerCast, Safety,
+ CastError, FnAbi, PointerCast, Safety, Variance,
},
// FIXME: Properly encapsulate mir
hir_ty::{mir, Interner as ChalkTyInterner},
@@ -699,7 +699,7 @@ impl Module {
let source_map = tree_source_maps.impl_(loc.id.value).item();
let node = &tree[loc.id.value];
let file_id = loc.id.file_id();
- if file_id.macro_file().map_or(false, |it| it.is_builtin_derive(db.upcast())) {
+ if file_id.macro_file().is_some_and(|it| it.is_builtin_derive(db.upcast())) {
// these expansion come from us, diagnosing them is a waste of resources
// FIXME: Once we diagnose the inputs to builtin derives, we should at least extract those diagnostics somehow
continue;
@@ -724,7 +724,7 @@ impl Module {
}
let trait_ = impl_def.trait_(db);
- let trait_is_unsafe = trait_.map_or(false, |t| t.is_unsafe(db));
+ let trait_is_unsafe = trait_.is_some_and(|t| t.is_unsafe(db));
let impl_is_negative = impl_def.is_negative(db);
let impl_is_unsafe = impl_def.is_unsafe(db);
@@ -2778,11 +2778,11 @@ impl Trait {
}
pub fn is_auto(self, db: &dyn HirDatabase) -> bool {
- db.trait_data(self.id).is_auto
+ db.trait_data(self.id).flags.contains(TraitFlags::IS_AUTO)
}
pub fn is_unsafe(&self, db: &dyn HirDatabase) -> bool {
- db.trait_data(self.id).is_unsafe
+ db.trait_data(self.id).flags.contains(TraitFlags::IS_UNSAFE)
}
pub fn type_or_const_param_count(
@@ -3574,6 +3574,61 @@ impl GenericDef {
}
}
+// We cannot call this `Substitution` unfortunately...
+#[derive(Debug)]
+pub struct GenericSubstitution {
+ def: GenericDefId,
+ subst: Substitution,
+ env: Arc<TraitEnvironment>,
+}
+
+impl GenericSubstitution {
+ fn new(def: GenericDefId, subst: Substitution, env: Arc<TraitEnvironment>) -> Self {
+ Self { def, subst, env }
+ }
+
+ pub fn types(&self, db: &dyn HirDatabase) -> Vec<(Symbol, Type)> {
+ let container = match self.def {
+ GenericDefId::ConstId(id) => Some(id.lookup(db.upcast()).container),
+ GenericDefId::FunctionId(id) => Some(id.lookup(db.upcast()).container),
+ GenericDefId::TypeAliasId(id) => Some(id.lookup(db.upcast()).container),
+ _ => None,
+ };
+ let container_type_params = container
+ .and_then(|container| match container {
+ ItemContainerId::ImplId(container) => Some(container.into()),
+ ItemContainerId::TraitId(container) => Some(container.into()),
+ _ => None,
+ })
+ .map(|container| {
+ db.generic_params(container)
+ .iter_type_or_consts()
+ .filter_map(|param| match param.1 {
+ TypeOrConstParamData::TypeParamData(param) => Some(param.name.clone()),
+ TypeOrConstParamData::ConstParamData(_) => None,
+ })
+ .collect::<Vec<_>>()
+ });
+ let generics = db.generic_params(self.def);
+ let type_params = generics.iter_type_or_consts().filter_map(|param| match param.1 {
+ TypeOrConstParamData::TypeParamData(param) => Some(param.name.clone()),
+ TypeOrConstParamData::ConstParamData(_) => None,
+ });
+ // The `Substitution` is first self then container, we want the reverse order.
+ let self_params = self.subst.type_parameters(Interner).zip(type_params);
+ let container_params = self.subst.as_slice(Interner)[generics.len()..]
+ .iter()
+ .filter_map(|param| param.ty(Interner).cloned())
+ .zip(container_type_params.into_iter().flatten());
+ container_params
+ .chain(self_params)
+ .filter_map(|(ty, name)| {
+ Some((name?.symbol().clone(), Type { ty, env: self.env.clone() }))
+ })
+ .collect()
+ }
+}
+
/// A single local definition.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct Local {
@@ -3902,6 +3957,22 @@ impl GenericParam {
GenericParam::LifetimeParam(it) => it.id.parent.into(),
}
}
+
+ pub fn variance(self, db: &dyn HirDatabase) -> Option<Variance> {
+ let parent = match self {
+ GenericParam::TypeParam(it) => it.id.parent(),
+ // const parameters are always invariant
+ GenericParam::ConstParam(_) => return None,
+ GenericParam::LifetimeParam(it) => it.id.parent,
+ };
+ let generics = hir_ty::generics::generics(db.upcast(), parent);
+ let index = match self {
+ GenericParam::TypeParam(it) => generics.type_or_const_param_idx(it.id.into())?,
+ GenericParam::ConstParam(_) => return None,
+ GenericParam::LifetimeParam(it) => generics.lifetime_idx(it.id)?,
+ };
+ db.variances_of(parent)?.get(index).copied()
+ }
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
@@ -5152,21 +5223,18 @@ impl Type {
) -> Option<T> {
let _p = tracing::info_span!("iterate_method_candidates_with_traits").entered();
let mut slot = None;
-
- self.iterate_method_candidates_dyn(
+ self.iterate_method_candidates_split_inherent(
db,
scope,
traits_in_scope,
with_local_impls,
name,
- &mut |assoc_item_id| {
- if let AssocItemId::FunctionId(func) = assoc_item_id {
- if let Some(res) = callback(func.into()) {
- slot = Some(res);
- return ControlFlow::Break(());
- }
+ |f| match callback(f) {
+ it @ Some(_) => {
+ slot = it;
+ ControlFlow::Break(())
}
- ControlFlow::Continue(())
+ None => ControlFlow::Continue(()),
},
);
slot
@@ -5190,15 +5258,49 @@ impl Type {
)
}
- fn iterate_method_candidates_dyn(
+ /// Allows you to treat inherent and non-inherent methods differently.
+ ///
+ /// Note that inherent methods may actually be trait methods! For example, in `dyn Trait`, the trait's methods
+ /// are considered inherent methods.
+ pub fn iterate_method_candidates_split_inherent(
&self,
db: &dyn HirDatabase,
scope: &SemanticsScope<'_>,
traits_in_scope: &FxHashSet<TraitId>,
with_local_impls: Option<Module>,
name: Option<&Name>,
- callback: &mut dyn FnMut(AssocItemId) -> ControlFlow<()>,
+ callback: impl MethodCandidateCallback,
) {
+ struct Callback<T>(T);
+
+ impl<T: MethodCandidateCallback> method_resolution::MethodCandidateCallback for Callback<T> {
+ fn on_inherent_method(
+ &mut self,
+ _adjustments: method_resolution::ReceiverAdjustments,
+ item: AssocItemId,
+ _is_visible: bool,
+ ) -> ControlFlow<()> {
+ if let AssocItemId::FunctionId(func) = item {
+ self.0.on_inherent_method(func.into())
+ } else {
+ ControlFlow::Continue(())
+ }
+ }
+
+ fn on_trait_method(
+ &mut self,
+ _adjustments: method_resolution::ReceiverAdjustments,
+ item: AssocItemId,
+ _is_visible: bool,
+ ) -> ControlFlow<()> {
+ if let AssocItemId::FunctionId(func) = item {
+ self.0.on_trait_method(func.into())
+ } else {
+ ControlFlow::Continue(())
+ }
+ }
+ }
+
let _p = tracing::info_span!(
"iterate_method_candidates_dyn",
with_local_impls = traits_in_scope.len(),
@@ -5223,7 +5325,7 @@ impl Type {
with_local_impls.and_then(|b| b.id.containing_block()).into(),
name,
method_resolution::LookupMode::MethodCall,
- &mut |_adj, id, _| callback(id),
+ &mut Callback(callback),
);
}
@@ -5239,33 +5341,61 @@ impl Type {
) -> Option<T> {
let _p = tracing::info_span!("iterate_path_candidates").entered();
let mut slot = None;
- self.iterate_path_candidates_dyn(
+
+ self.iterate_path_candidates_split_inherent(
db,
scope,
traits_in_scope,
with_local_impls,
name,
- &mut |assoc_item_id| {
- if let Some(res) = callback(assoc_item_id.into()) {
- slot = Some(res);
- return ControlFlow::Break(());
+ |item| match callback(item) {
+ it @ Some(_) => {
+ slot = it;
+ ControlFlow::Break(())
}
- ControlFlow::Continue(())
+ None => ControlFlow::Continue(()),
},
);
slot
}
+ /// Iterates over inherent methods.
+ ///
+ /// In some circumstances, inherent methods methods may actually be trait methods!
+ /// For example, when `dyn Trait` is a receiver, _trait_'s methods would be considered
+ /// to be inherent methods.
#[tracing::instrument(skip_all, fields(name = ?name))]
- fn iterate_path_candidates_dyn(
+ pub fn iterate_path_candidates_split_inherent(
&self,
db: &dyn HirDatabase,
scope: &SemanticsScope<'_>,
traits_in_scope: &FxHashSet<TraitId>,
with_local_impls: Option<Module>,
name: Option<&Name>,
- callback: &mut dyn FnMut(AssocItemId) -> ControlFlow<()>,
+ callback: impl PathCandidateCallback,
) {
+ struct Callback<T>(T);
+
+ impl<T: PathCandidateCallback> method_resolution::MethodCandidateCallback for Callback<T> {
+ fn on_inherent_method(
+ &mut self,
+ _adjustments: method_resolution::ReceiverAdjustments,
+ item: AssocItemId,
+ _is_visible: bool,
+ ) -> ControlFlow<()> {
+ self.0.on_inherent_item(item.into())
+ }
+
+ fn on_trait_method(
+ &mut self,
+ _adjustments: method_resolution::ReceiverAdjustments,
+ item: AssocItemId,
+ _is_visible: bool,
+ ) -> ControlFlow<()> {
+ self.0.on_trait_item(item.into())
+ }
+ }
+
let canonical = hir_ty::replace_errors_with_variables(&self.ty);
let krate = scope.krate();
@@ -5281,7 +5411,7 @@ impl Type {
traits_in_scope,
with_local_impls.and_then(|b| b.id.containing_block()).into(),
name,
- callback,
+ &mut Callback(callback),
);
}
@@ -5862,6 +5992,12 @@ impl HasCrate for Adt {
}
}
+impl HasCrate for Impl {
+ fn krate(&self, db: &dyn HirDatabase) -> Crate {
+ self.module(db).krate()
+ }
+}
+
impl HasCrate for Module {
fn krate(&self, _: &dyn HirDatabase) -> Crate {
Module::krate(*self)
@@ -5983,3 +6119,41 @@ fn push_ty_diagnostics(
);
}
}
+
+pub trait MethodCandidateCallback {
+ fn on_inherent_method(&mut self, f: Function) -> ControlFlow<()>;
+
+ fn on_trait_method(&mut self, f: Function) -> ControlFlow<()>;
+}
+
+impl<F> MethodCandidateCallback for F
+where
+ F: FnMut(Function) -> ControlFlow<()>,
+{
+ fn on_inherent_method(&mut self, f: Function) -> ControlFlow<()> {
+ self(f)
+ }
+
+ fn on_trait_method(&mut self, f: Function) -> ControlFlow<()> {
+ self(f)
+ }
+}
+
+pub trait PathCandidateCallback {
+ fn on_inherent_item(&mut self, item: AssocItem) -> ControlFlow<()>;
+
+ fn on_trait_item(&mut self, item: AssocItem) -> ControlFlow<()>;
+}
+
+impl<F> PathCandidateCallback for F
+where
+ F: FnMut(AssocItem) -> ControlFlow<()>,
+{
+ fn on_inherent_item(&mut self, item: AssocItem) -> ControlFlow<()> {
+ self(item)
+ }
+
+ fn on_trait_item(&mut self, item: AssocItem) -> ControlFlow<()> {
+ self(item)
+ }
+}