Unnamed repository; edit this file 'description' to name the repository.
-rw-r--r--crates/hir/src/lib.rs4
-rw-r--r--crates/hir/src/term_search.rs1
-rw-r--r--crates/hir/src/term_search/tactics.rs58
-rw-r--r--crates/ide-assists/src/handlers/term_search.rs20
4 files changed, 82 insertions, 1 deletions
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 14066dee5f..f157b11df5 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -4321,8 +4321,10 @@ impl Type {
self.ty
.strip_references()
.as_adt()
+ .map(|(_, substs)| substs)
+ .or_else(|| self.ty.strip_references().as_tuple())
.into_iter()
- .flat_map(|(_, substs)| substs.iter(Interner))
+ .flat_map(|substs| substs.iter(Interner))
.filter_map(|arg| arg.ty(Interner).cloned())
.map(move |ty| self.derived(ty))
}
diff --git a/crates/hir/src/term_search.rs b/crates/hir/src/term_search.rs
index 68244b1272..93e7300491 100644
--- a/crates/hir/src/term_search.rs
+++ b/crates/hir/src/term_search.rs
@@ -311,6 +311,7 @@ pub fn term_search<DB: HirDatabase>(ctx: &TermSearchCtx<'_, DB>) -> Vec<Expr> {
solutions.extend(tactics::impl_method(ctx, &defs, &mut lookup));
solutions.extend(tactics::struct_projection(ctx, &defs, &mut lookup));
solutions.extend(tactics::impl_static_method(ctx, &defs, &mut lookup));
+ solutions.extend(tactics::make_tuple(ctx, &defs, &mut lookup));
// Discard not interesting `ScopeDef`s for speedup
for def in lookup.exhausted_scopedefs() {
diff --git a/crates/hir/src/term_search/tactics.rs b/crates/hir/src/term_search/tactics.rs
index 93a780d470..102e0ca4c3 100644
--- a/crates/hir/src/term_search/tactics.rs
+++ b/crates/hir/src/term_search/tactics.rs
@@ -872,3 +872,61 @@ pub(super) fn impl_static_method<'a, DB: HirDatabase>(
.filter_map(|(ty, exprs)| ty.could_unify_with_deeply(db, &ctx.goal).then_some(exprs))
.flatten()
}
+
+/// # Make tuple tactic
+///
+/// Attempts to create tuple types if any are listed in types wishlist
+///
+/// Updates lookup by new types reached and returns iterator that yields
+/// elements that unify with `goal`.
+///
+/// # Arguments
+/// * `ctx` - Context for the term search
+/// * `defs` - Set of items in scope at term search target location
+/// * `lookup` - Lookup table for types
+pub(super) fn make_tuple<'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();
+
+ lookup
+ .types_wishlist()
+ .clone()
+ .into_iter()
+ .filter(|ty| ty.is_tuple())
+ .filter_map(move |ty| {
+ // Double check to not contain unknown
+ if ty.contains_unknown() {
+ return None;
+ }
+
+ // Ignore types that have something to do with lifetimes
+ if ctx.config.enable_borrowcheck && ty.contains_reference(db) {
+ return None;
+ }
+
+ // Early exit if some param cannot be filled from lookup
+ let param_exprs: Vec<Vec<Expr>> =
+ ty.type_arguments().map(|field| lookup.find(db, &field)).collect::<Option<_>>()?;
+
+ let exprs: Vec<Expr> = param_exprs
+ .into_iter()
+ .multi_cartesian_product()
+ .map(|params| {
+ let tys: Vec<Type> = params.iter().map(|it| it.ty(db)).collect();
+ let tuple_ty = Type::new_tuple(module.krate().into(), &tys);
+
+ let expr = Expr::Tuple { ty: tuple_ty.clone(), params };
+ lookup.insert(tuple_ty, iter::once(expr.clone()));
+ expr
+ })
+ .collect();
+
+ Some(exprs)
+ })
+ .flatten()
+ .filter_map(|expr| expr.ty(db).could_unify_with_deeply(db, &ctx.goal).then_some(expr))
+}
diff --git a/crates/ide-assists/src/handlers/term_search.rs b/crates/ide-assists/src/handlers/term_search.rs
index fa32a3bbe7..0f4a8e3aec 100644
--- a/crates/ide-assists/src/handlers/term_search.rs
+++ b/crates/ide-assists/src/handlers/term_search.rs
@@ -253,4 +253,24 @@ fn g() { let a = &1; let b: f32 = f(a); }"#,
fn g() { let a = &mut 1; let b: f32 = todo$0!(); }"#,
)
}
+
+ #[test]
+ fn test_tuple_simple() {
+ check_assist(
+ term_search,
+ r#"//- minicore: todo, unimplemented
+fn f() { let a = 1; let b = 0.0; let c: (i32, f64) = todo$0!(); }"#,
+ r#"fn f() { let a = 1; let b = 0.0; let c: (i32, f64) = (a, b); }"#,
+ )
+ }
+
+ #[test]
+ fn test_tuple_nested() {
+ check_assist(
+ term_search,
+ r#"//- minicore: todo, unimplemented
+fn f() { let a = 1; let b = 0.0; let c: (i32, (i32, f64)) = todo$0!(); }"#,
+ r#"fn f() { let a = 1; let b = 0.0; let c: (i32, (i32, f64)) = (a, (a, b)); }"#,
+ )
+ }
}