diff --git a/src/tools/rust-analyzer/crates/hir-def/src/generics.rs b/src/tools/rust-analyzer/crates/hir-def/src/generics.rs index 3a277ecb90b..10a1d65bb93 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/generics.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/generics.rs @@ -377,7 +377,7 @@ fn fill_impl_trait_bounds(&mut self, impl_bounds: Vec>>) } } - pub(crate) fn fill_implicit_impl_trait_args( + fn fill_implicit_impl_trait_args( &mut self, db: &dyn DefDatabase, exp: &mut Lazy<(Arc, Expander), impl FnOnce() -> (Arc, Expander)>, diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs index 6aa5a63d628..199b8daa37e 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs @@ -662,7 +662,7 @@ fn lower_generic_params( let attrs = RawAttrs::new(self.db.upcast(), ¶m, self.body_ctx.span_map()); debug_assert!(self.generic_param_attr_buffer.insert(item, attrs).is_none()); }; - + self.body_ctx.take_impl_traits_bounds(); let mut generics = GenericParamsCollector::default(); if let HasImplicitSelf::Yes(bounds) = has_implicit_self { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs index 706b034821e..04e2ded05a5 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs @@ -345,51 +345,43 @@ pub fn lower_ty_ext(&self, type_ref: &TypeRef) -> (Ty, Option) { } ImplTraitLoweringState::Param(counter) => { let idx = counter.get(); - // FIXME we're probably doing something wrong here - counter.set(idx + count_impl_traits(type_ref) as u16); - if let Some(generics) = self.generics() { - let param = generics - .iter() - .filter(|(_, data)| { - matches!( - data, - GenericParamDataRef::TypeParamData(data) - if data.provenance == TypeParamProvenance::ArgumentImplTrait - ) - }) - .nth(idx as usize) - .map_or(TyKind::Error, |(id, _)| { - if let GenericParamId::TypeParamId(id) = id { - TyKind::Placeholder(to_placeholder_idx(self.db, id.into())) - } else { - // we just filtered them out - unreachable!("Unexpected lifetime or const argument"); - } - }); - param.intern(Interner) - } else { - TyKind::Error.intern(Interner) - } + counter.set(idx + 1); + let kind = self + .generics() + .expect("param impl trait lowering must be in a generic def") + .iter() + .filter_map(|(id, data)| match (id, data) { + ( + GenericParamId::TypeParamId(id), + GenericParamDataRef::TypeParamData(data), + ) if data.provenance == TypeParamProvenance::ArgumentImplTrait => { + Some(id) + } + _ => None, + }) + .nth(idx as usize) + .map_or(TyKind::Error, |id| { + TyKind::Placeholder(to_placeholder_idx(self.db, id.into())) + }); + kind.intern(Interner) } ImplTraitLoweringState::Variable(counter) => { let idx = counter.get(); - // FIXME we're probably doing something wrong here - counter.set(idx + count_impl_traits(type_ref) as u16); + counter.set(idx + 1); let ( _parent_params, self_params, - list_params, + type_params, const_params, _impl_trait_params, _lifetime_params, - ) = if let Some(generics) = self.generics() { - generics.provenance_split() - } else { - (0, 0, 0, 0, 0, 0) - }; + ) = self + .generics() + .expect("variable impl trait lowering must be in a generic def") + .provenance_split(); TyKind::BoundVar(BoundVar::new( self.in_binders, - idx as usize + self_params + list_params + const_params, + idx as usize + self_params + type_params + const_params, )) .intern(Interner) } @@ -1150,84 +1142,77 @@ fn assoc_type_bindings_from_type_bound( binding.type_ref.as_ref().map_or(0, |_| 1) + binding.bounds.len(), ); if let Some(type_ref) = &binding.type_ref { - if let ( - TypeRef::ImplTrait(bounds), - ImplTraitLoweringState::Param(_) - | ImplTraitLoweringState::Variable(_) - | ImplTraitLoweringState::Disallowed, - ) = (type_ref, &self.impl_trait_mode) - { - for bound in bounds { - predicates.extend( - self.lower_type_bound( - bound, - TyKind::Alias(AliasTy::Projection(projection_ty.clone())) - .intern(Interner), - false, - ), - ); + match (type_ref, &self.impl_trait_mode) { + (TypeRef::ImplTrait(_), ImplTraitLoweringState::Disallowed) => (), + ( + _, + ImplTraitLoweringState::Disallowed | ImplTraitLoweringState::Opaque(_), + ) => { + let ty = self.lower_ty(type_ref); + let alias_eq = + AliasEq { alias: AliasTy::Projection(projection_ty.clone()), ty }; + predicates + .push(crate::wrap_empty_binders(WhereClause::AliasEq(alias_eq))); } - } else { - let ty = 'ty: { - if matches!( - self.impl_trait_mode, - ImplTraitLoweringState::Param(_) - | ImplTraitLoweringState::Variable(_) - ) { - // Find the generic index for the target of our `bound` - let target_param_idx = self - .resolver - .where_predicates_in_scope() - .find_map(|(p, _)| match p { - WherePredicate::TypeBound { - target: WherePredicateTypeTarget::TypeOrConstParam(idx), - bound: b, - } if b == bound => Some(idx), - _ => None, - }); - if let Some(target_param_idx) = target_param_idx { - let mut counter = 0; - let generics = self.generics().expect("generics in scope"); - for (idx, data) in generics.params.type_or_consts.iter() { - // Count the number of `impl Trait` things that appear before - // the target of our `bound`. - // Our counter within `impl_trait_mode` should be that number - // to properly lower each types within `type_ref` - if data.type_param().is_some_and(|p| { - p.provenance == TypeParamProvenance::ArgumentImplTrait - }) { - counter += 1; - } - if idx == *target_param_idx { - break; - } + ( + _, + ImplTraitLoweringState::Param(_) | ImplTraitLoweringState::Variable(_), + ) => { + // Find the generic index for the target of our `bound` + let target_param_idx = self + .resolver + .where_predicates_in_scope() + .find_map(|(p, _)| match p { + WherePredicate::TypeBound { + target: WherePredicateTypeTarget::TypeOrConstParam(idx), + bound: b, + } if b == bound => Some(idx), + _ => None, + }); + let ty = if let Some(target_param_idx) = target_param_idx { + let mut counter = 0; + let generics = self.generics().expect("generics in scope"); + for (idx, data) in generics.params.type_or_consts.iter() { + // Count the number of `impl Trait` things that appear before + // the target of our `bound`. + // Our counter within `impl_trait_mode` should be that number + // to properly lower each types within `type_ref` + if data.type_param().is_some_and(|p| { + p.provenance == TypeParamProvenance::ArgumentImplTrait + }) { + counter += 1; } - let mut ext = TyLoweringContext::new_maybe_unowned( - self.db, - self.resolver, - self.owner, - ) - .with_type_param_mode(self.type_param_mode); - match &self.impl_trait_mode { - ImplTraitLoweringState::Param(_) => { - ext.impl_trait_mode = - ImplTraitLoweringState::Param(Cell::new(counter)); - } - ImplTraitLoweringState::Variable(_) => { - ext.impl_trait_mode = ImplTraitLoweringState::Variable( - Cell::new(counter), - ); - } - _ => unreachable!(), + if idx == *target_param_idx { + break; } - break 'ty ext.lower_ty(type_ref); } - } - self.lower_ty(type_ref) - }; - let alias_eq = - AliasEq { alias: AliasTy::Projection(projection_ty.clone()), ty }; - predicates.push(crate::wrap_empty_binders(WhereClause::AliasEq(alias_eq))); + let mut ext = TyLoweringContext::new_maybe_unowned( + self.db, + self.resolver, + self.owner, + ) + .with_type_param_mode(self.type_param_mode); + match &self.impl_trait_mode { + ImplTraitLoweringState::Param(_) => { + ext.impl_trait_mode = + ImplTraitLoweringState::Param(Cell::new(counter)); + } + ImplTraitLoweringState::Variable(_) => { + ext.impl_trait_mode = + ImplTraitLoweringState::Variable(Cell::new(counter)); + } + _ => unreachable!(), + } + ext.lower_ty(type_ref) + } else { + self.lower_ty(type_ref) + }; + + let alias_eq = + AliasEq { alias: AliasTy::Projection(projection_ty.clone()), ty }; + predicates + .push(crate::wrap_empty_binders(WhereClause::AliasEq(alias_eq))); + } } } for bound in binding.bounds.iter() { @@ -1394,16 +1379,6 @@ pub fn lower_lifetime(&self, lifetime: &LifetimeRef) -> Lifetime { } } -fn count_impl_traits(type_ref: &TypeRef) -> usize { - let mut count = 0; - type_ref.walk(&mut |type_ref| { - if matches!(type_ref, TypeRef::ImplTrait(_)) { - count += 1; - } - }); - count -} - /// Build the signature of a callable item (function, struct or enum variant). pub(crate) fn callable_item_sig(db: &dyn HirDatabase, def: CallableDefId) -> PolyFnSig { match def { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs index 69c7a815488..f80d5394985 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs @@ -1975,3 +1975,24 @@ impl<#[cfg(feature = "a-feature")] A> Bar for (){} "#, ) } + +#[test] +fn nested_anon_generics_and_where_bounds_17173() { + check_types( + r#" +//- minicore: sized +pub trait Lookup { + type Data; + fn lookup(&self) -> Self::Data; +} +pub trait ItemTreeLoc { + type Id; +} +fn id_to_generics(id: impl Lookup>) + //^^ impl Lookup> +where + (): Sized, +{} +"#, + ); +}