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.rs | 230 |
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) + } +} |