Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-def/src/generics.rs')
| -rw-r--r-- | crates/hir-def/src/generics.rs | 118 |
1 files changed, 74 insertions, 44 deletions
diff --git a/crates/hir-def/src/generics.rs b/crates/hir-def/src/generics.rs index acc60e1d9e..10a1d65bb9 100644 --- a/crates/hir-def/src/generics.rs +++ b/crates/hir-def/src/generics.rs @@ -20,7 +20,7 @@ use triomphe::Arc; use crate::{ db::DefDatabase, expander::Expander, - item_tree::{GenericsItemTreeNode, ItemTree}, + item_tree::{AttrOwner, FileItemTreeId, GenericModItem, GenericsItemTreeNode, ItemTree}, lower::LowerCtx, nameres::{DefMap, MacroSubNs}, type_ref::{ConstRef, LifetimeRef, TypeBound, TypeRef}, @@ -339,6 +339,7 @@ impl GenericParamsCollector { target: Either<TypeRef, LifetimeRef>, ) { let bound = TypeBound::from_ast(lower_ctx, bound); + self.fill_impl_trait_bounds(lower_ctx.take_impl_traits_bounds()); let predicate = match (target, bound) { (Either::Left(type_ref), bound) => match hrtb_lifetimes { Some(hrtb_lifetimes) => WherePredicate::ForLifetime { @@ -359,7 +360,24 @@ impl GenericParamsCollector { self.where_predicates.push(predicate); } - pub(crate) fn fill_implicit_impl_trait_args( + fn fill_impl_trait_bounds(&mut self, impl_bounds: Vec<Vec<Interned<TypeBound>>>) { + for bounds in impl_bounds { + let param = TypeParamData { + name: None, + default: None, + provenance: TypeParamProvenance::ArgumentImplTrait, + }; + let param_id = self.type_or_consts.alloc(param.into()); + for bound in bounds { + self.where_predicates.push(WherePredicate::TypeBound { + target: WherePredicateTypeTarget::TypeOrConstParam(param_id), + bound, + }); + } + } + } + + fn fill_implicit_impl_trait_args( &mut self, db: &dyn DefDatabase, exp: &mut Lazy<(Arc<DefMap>, Expander), impl FnOnce() -> (Arc<DefMap>, Expander)>, @@ -456,56 +474,67 @@ impl GenericParams { let cfg_options = &cfg_options[krate].cfg_options; // Returns the generic parameters that are enabled under the current `#[cfg]` options - let enabled_params = |params: &Interned<GenericParams>, item_tree: &ItemTree| { - let enabled = |param| item_tree.attrs(db, krate, param).is_cfg_enabled(cfg_options); - - // In the common case, no parameters will by disabled by `#[cfg]` attributes. - // Therefore, make a first pass to check if all parameters are enabled and, if so, - // clone the `Interned<GenericParams>` instead of recreating an identical copy. - let all_type_or_consts_enabled = - params.type_or_consts.iter().all(|(idx, _)| enabled(idx.into())); - let all_lifetimes_enabled = params.lifetimes.iter().all(|(idx, _)| enabled(idx.into())); - - if all_type_or_consts_enabled && all_lifetimes_enabled { - params.clone() - } else { - Interned::new(GenericParams { - type_or_consts: all_type_or_consts_enabled - .then(|| params.type_or_consts.clone()) - .unwrap_or_else(|| { - params - .type_or_consts - .iter() - .filter(|(idx, _)| enabled((*idx).into())) - .map(|(_, param)| param.clone()) - .collect() - }), - lifetimes: all_lifetimes_enabled - .then(|| params.lifetimes.clone()) - .unwrap_or_else(|| { - params - .lifetimes - .iter() - .filter(|(idx, _)| enabled((*idx).into())) - .map(|(_, param)| param.clone()) - .collect() - }), - where_predicates: params.where_predicates.clone(), - }) - } - }; + let enabled_params = + |params: &Interned<GenericParams>, item_tree: &ItemTree, parent: GenericModItem| { + let enabled = |param| item_tree.attrs(db, krate, param).is_cfg_enabled(cfg_options); + let attr_owner_ct = |param| AttrOwner::TypeOrConstParamData(parent, param); + let attr_owner_lt = |param| AttrOwner::LifetimeParamData(parent, param); + + // In the common case, no parameters will by disabled by `#[cfg]` attributes. + // Therefore, make a first pass to check if all parameters are enabled and, if so, + // clone the `Interned<GenericParams>` instead of recreating an identical copy. + let all_type_or_consts_enabled = + params.type_or_consts.iter().all(|(idx, _)| enabled(attr_owner_ct(idx))); + let all_lifetimes_enabled = + params.lifetimes.iter().all(|(idx, _)| enabled(attr_owner_lt(idx))); + + if all_type_or_consts_enabled && all_lifetimes_enabled { + params.clone() + } else { + Interned::new(GenericParams { + type_or_consts: all_type_or_consts_enabled + .then(|| params.type_or_consts.clone()) + .unwrap_or_else(|| { + params + .type_or_consts + .iter() + .filter(|&(idx, _)| enabled(attr_owner_ct(idx))) + .map(|(_, param)| param.clone()) + .collect() + }), + lifetimes: all_lifetimes_enabled + .then(|| params.lifetimes.clone()) + .unwrap_or_else(|| { + params + .lifetimes + .iter() + .filter(|&(idx, _)| enabled(attr_owner_lt(idx))) + .map(|(_, param)| param.clone()) + .collect() + }), + where_predicates: params.where_predicates.clone(), + }) + } + }; fn id_to_generics<Id: GenericsItemTreeNode>( db: &dyn DefDatabase, id: impl for<'db> Lookup< Database<'db> = dyn DefDatabase + 'db, Data = impl ItemTreeLoc<Id = Id>, >, - enabled_params: impl Fn(&Interned<GenericParams>, &ItemTree) -> Interned<GenericParams>, - ) -> Interned<GenericParams> { + enabled_params: impl Fn( + &Interned<GenericParams>, + &ItemTree, + GenericModItem, + ) -> Interned<GenericParams>, + ) -> Interned<GenericParams> + where + FileItemTreeId<Id>: Into<GenericModItem>, + { let id = id.lookup(db).item_tree_id(); let tree = id.item_tree(db); let item = &tree[id.value]; - enabled_params(item.generic_params(), &tree) + enabled_params(item.generic_params(), &tree, id.value.into()) } match def { @@ -514,7 +543,8 @@ impl GenericParams { let tree = loc.id.item_tree(db); let item = &tree[loc.id.value]; - let enabled_params = enabled_params(&item.explicit_generic_params, &tree); + let enabled_params = + enabled_params(&item.explicit_generic_params, &tree, loc.id.value.into()); let module = loc.container.module(db); let func_data = db.function_data(id); |