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 7a701a48bf7..3a277ecb90b 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/generics.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/generics.rs @@ -339,6 +339,7 @@ impl GenericParamsCollector { target: Either, ) { 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,6 +360,23 @@ impl GenericParamsCollector { self.where_predicates.push(predicate); } + fn fill_impl_trait_bounds(&mut self, impl_bounds: Vec>>) { + 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, + }); + } + } + } + pub(crate) fn fill_implicit_impl_trait_args( &mut self, db: &dyn DefDatabase, diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/lower.rs index d574d80a8e0..e2f6cffa2f7 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/lower.rs @@ -1,26 +1,34 @@ //! Context for lowering paths. -use std::cell::OnceCell; +use std::cell::{OnceCell, RefCell}; use hir_expand::{ span_map::{SpanMap, SpanMapRef}, AstId, HirFileId, InFile, }; +use intern::Interned; use span::{AstIdMap, AstIdNode}; use syntax::ast; use triomphe::Arc; -use crate::{db::DefDatabase, path::Path}; +use crate::{db::DefDatabase, path::Path, type_ref::TypeBound}; pub struct LowerCtx<'a> { pub db: &'a dyn DefDatabase, file_id: HirFileId, span_map: OnceCell, ast_id_map: OnceCell>, + impl_trait_bounds: RefCell>>>, } impl<'a> LowerCtx<'a> { pub fn new(db: &'a dyn DefDatabase, file_id: HirFileId) -> Self { - LowerCtx { db, file_id, span_map: OnceCell::new(), ast_id_map: OnceCell::new() } + LowerCtx { + db, + file_id, + span_map: OnceCell::new(), + ast_id_map: OnceCell::new(), + impl_trait_bounds: RefCell::new(Vec::new()), + } } pub fn with_span_map_cell( @@ -28,7 +36,13 @@ impl<'a> LowerCtx<'a> { file_id: HirFileId, span_map: OnceCell, ) -> Self { - LowerCtx { db, file_id, span_map, ast_id_map: OnceCell::new() } + LowerCtx { + db, + file_id, + span_map, + ast_id_map: OnceCell::new(), + impl_trait_bounds: RefCell::new(Vec::new()), + } } pub(crate) fn span_map(&self) -> SpanMapRef<'_> { @@ -45,4 +59,12 @@ impl<'a> LowerCtx<'a> { self.ast_id_map.get_or_init(|| self.db.ast_id_map(self.file_id)).ast_id(item), ) } + + pub fn update_impl_traits_bounds(&self, bounds: Vec>) { + self.impl_trait_bounds.borrow_mut().push(bounds); + } + + pub fn take_impl_traits_bounds(&self) -> Vec>> { + self.impl_trait_bounds.borrow_mut().drain(..).collect() + } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs index b3c41a073c6..6af52614111 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs @@ -208,6 +208,13 @@ pub(super) fn lower_generic_args( .and_then(|args| lower_generic_args(lower_ctx, args)) .map(Interned::new); let type_ref = assoc_type_arg.ty().map(|it| TypeRef::from_ast(lower_ctx, it)); + let type_ref = type_ref.inspect(|tr| { + tr.walk(&mut |tr| { + if let TypeRef::ImplTrait(bounds) = tr { + lower_ctx.update_impl_traits_bounds(bounds.clone()); + } + }); + }); let bounds = if let Some(l) = assoc_type_arg.type_bound_list() { l.bounds() .map(|it| Interned::new(TypeBound::from_ast(lower_ctx, it))) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs index fadab858aa1..1602b173858 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs @@ -1,5 +1,5 @@ //! Name resolution façade. -use std::{fmt, hash::BuildHasherDefault, mem}; +use std::{fmt, hash::BuildHasherDefault, iter, mem}; use base_db::CrateId; use hir_expand::{ @@ -591,13 +591,13 @@ impl Resolver { pub fn where_predicates_in_scope( &self, - ) -> impl Iterator { + ) -> impl Iterator { self.scopes() .filter_map(|scope| match scope { - Scope::GenericParams { params, .. } => Some(params), + Scope::GenericParams { params, def } => Some((params, def)), _ => None, }) - .flat_map(|params| params.where_predicates.iter()) + .flat_map(|(params, def)| params.where_predicates.iter().zip(iter::repeat(def))) } pub fn generic_def(&self) -> Option { 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 7423c9ed327..706b034821e 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs @@ -1010,6 +1010,7 @@ impl<'a> TyLoweringContext<'a> { pub(crate) fn lower_where_predicate<'b>( &'b self, where_predicate: &'b WherePredicate, + &def: &GenericDefId, ignore_bindings: bool, ) -> impl Iterator + 'b { match where_predicate { @@ -1018,7 +1019,6 @@ impl<'a> TyLoweringContext<'a> { let self_ty = match target { WherePredicateTypeTarget::TypeRef(type_ref) => self.lower_ty(type_ref), &WherePredicateTypeTarget::TypeOrConstParam(local_id) => { - let def = self.resolver.generic_def().expect("generics in scope"); let param_id = hir_def::TypeOrConstParamId { parent: def, local_id }; match self.type_param_mode { ParamLoweringMode::Placeholder => { @@ -1178,7 +1178,7 @@ impl<'a> TyLoweringContext<'a> { let target_param_idx = self .resolver .where_predicates_in_scope() - .find_map(|p| match p { + .find_map(|(p, _)| match p { WherePredicate::TypeBound { target: WherePredicateTypeTarget::TypeOrConstParam(idx), bound: b, @@ -1559,7 +1559,7 @@ pub(crate) fn generic_predicates_for_param_query( let generics = generics(db.upcast(), def); // we have to filter out all other predicates *first*, before attempting to lower them - let predicate = |pred: &&_| match pred { + let predicate = |(pred, &def): &(&_, _)| match pred { WherePredicate::ForLifetime { target, bound, .. } | WherePredicate::TypeBound { target, bound, .. } => { let invalid_target = match target { @@ -1601,8 +1601,8 @@ pub(crate) fn generic_predicates_for_param_query( let mut predicates: Vec<_> = resolver .where_predicates_in_scope() .filter(predicate) - .flat_map(|pred| { - ctx.lower_where_predicate(pred, true).map(|p| make_binders(db, &generics, p)) + .flat_map(|(pred, def)| { + ctx.lower_where_predicate(pred, def, true).map(|p| make_binders(db, &generics, p)) }) .collect(); @@ -1655,8 +1655,8 @@ pub(crate) fn trait_environment_query( }; let mut traits_in_scope = Vec::new(); let mut clauses = Vec::new(); - for pred in resolver.where_predicates_in_scope() { - for pred in ctx.lower_where_predicate(pred, false) { + for (pred, def) in resolver.where_predicates_in_scope() { + for pred in ctx.lower_where_predicate(pred, def, false) { if let WhereClause::Implemented(tr) = &pred.skip_binders() { traits_in_scope.push((tr.self_type_parameter(Interner).clone(), tr.hir_trait_id())); } @@ -1710,8 +1710,8 @@ pub(crate) fn generic_predicates_query( let mut predicates = resolver .where_predicates_in_scope() - .flat_map(|pred| { - ctx.lower_where_predicate(pred, false).map(|p| make_binders(db, &generics, p)) + .flat_map(|(pred, def)| { + ctx.lower_where_predicate(pred, def, false).map(|p| make_binders(db, &generics, p)) }) .collect::>(); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs index 4bc3e121ac1..7a318877b72 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs @@ -4765,3 +4765,41 @@ fn test() { "#, ); } + +#[test] +fn associated_type_with_impl_trait_in_tuple() { + check_no_mismatches( + r#" +pub trait Iterator { + type Item; +} + +pub trait Value {} + +fn bar>() {} + +fn foo() { + bar(); +} +"#, + ); +} + +#[test] +fn associated_type_with_impl_trait_in_nested_tuple() { + check_no_mismatches( + r#" +pub trait Iterator { + type Item; +} + +pub trait Value {} + +fn bar>() {} + +fn foo() { + bar(); +} +"#, + ); +}