Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir/src/term_search/tactics.rs')
| -rw-r--r-- | crates/hir/src/term_search/tactics.rs | 52 |
1 files changed, 51 insertions, 1 deletions
diff --git a/crates/hir/src/term_search/tactics.rs b/crates/hir/src/term_search/tactics.rs index f95ff1dc0f..b738e6af77 100644 --- a/crates/hir/src/term_search/tactics.rs +++ b/crates/hir/src/term_search/tactics.rs @@ -5,6 +5,7 @@ //! * `defs` - Set of items in scope at term search target location //! * `lookup` - Lookup table for types //! * `should_continue` - Function that indicates when to stop iterating +//! //! And they return iterator that yields type trees that unify with the `goal` type. use std::iter; @@ -79,7 +80,10 @@ pub(super) fn trivial<'a, DB: HirDatabase>( lookup.insert(ty.clone(), std::iter::once(expr.clone())); // Don't suggest local references as they are not valid for return - if matches!(expr, Expr::Local(_)) && ty.contains_reference(db) { + if matches!(expr, Expr::Local(_)) + && ty.contains_reference(db) + && ctx.config.enable_borrowcheck + { return None; } @@ -87,6 +91,52 @@ pub(super) fn trivial<'a, DB: HirDatabase>( }) } +/// # Associated constant tactic +/// +/// Attempts to fulfill the goal by trying constants defined as associated items. +/// Only considers them on types that are in scope. +/// +/// # Arguments +/// * `ctx` - Context for the term search +/// * `defs` - Set of items in scope at term search target location +/// * `lookup` - Lookup table for types +/// +/// Returns iterator that yields elements that unify with `goal`. +/// +/// _Note that there is no use of calling this tactic in every iteration as the output does not +/// depend on the current state of `lookup`_ +pub(super) fn assoc_const<'a, DB: HirDatabase>( + ctx: &'a TermSearchCtx<'a, DB>, + defs: &'a FxHashSet<ScopeDef>, + lookup: &'a mut LookupTable, +) -> impl Iterator<Item = Expr> + 'a { + let db = ctx.sema.db; + let module = ctx.scope.module(); + + defs.iter() + .filter_map(|def| match def { + ScopeDef::ModuleDef(ModuleDef::Adt(it)) => Some(it), + _ => None, + }) + .flat_map(|it| Impl::all_for_type(db, it.ty(db))) + .filter(|it| !it.is_unsafe(db)) + .flat_map(|it| it.items(db)) + .filter(move |it| it.is_visible_from(db, module)) + .filter_map(AssocItem::as_const) + .filter_map(|it| { + let expr = Expr::Const(it); + let ty = it.ty(db); + + if ty.contains_unknown() { + return None; + } + + lookup.insert(ty.clone(), std::iter::once(expr.clone())); + + ty.could_unify_with_deeply(db, &ctx.goal).then_some(expr) + }) +} + /// # Data constructor tactic /// /// Attempts different data constructors for enums and structs in scope |