Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 8bd30e9

Browse files
committed
Improve generics handling in term search
1 parent 1d3558b commit 8bd30e9

File tree

6 files changed

+136
-73
lines changed

6 files changed

+136
-73
lines changed

crates/hir/src/lib.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3856,6 +3856,11 @@ impl Type {
38563856
Type { env: ty.env, ty: TyBuilder::slice(ty.ty) }
38573857
}
38583858

3859+
pub fn new_tuple(krate: CrateId, tys: &[Type]) -> Type {
3860+
let tys = tys.iter().map(|it| it.ty.clone());
3861+
Type { env: TraitEnvironment::empty(krate), ty: TyBuilder::tuple_with(tys) }
3862+
}
3863+
38593864
pub fn is_unit(&self) -> bool {
38603865
matches!(self.ty.kind(Interner), TyKind::Tuple(0, ..))
38613866
}

crates/hir/src/term_search.rs

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,10 @@ impl AlternativeExprs {
7272
AlternativeExprs::Many => (),
7373
}
7474
}
75+
76+
fn is_many(&self) -> bool {
77+
matches!(self, AlternativeExprs::Many)
78+
}
7579
}
7680

7781
/// # Lookup table for term search
@@ -103,27 +107,36 @@ struct LookupTable {
103107

104108
impl LookupTable {
105109
/// Initialize lookup table
106-
fn new(many_threshold: usize) -> Self {
110+
fn new(many_threshold: usize, goal: Type) -> Self {
107111
let mut res = Self { many_threshold, ..Default::default() };
108112
res.new_types.insert(NewTypesKey::ImplMethod, Vec::new());
109113
res.new_types.insert(NewTypesKey::StructProjection, Vec::new());
114+
res.types_wishlist.insert(goal);
110115
res
111116
}
112117

113118
/// Find all `Expr`s that unify with the `ty`
114-
fn find(&self, db: &dyn HirDatabase, ty: &Type) -> Option<Vec<Expr>> {
115-
self.data
119+
fn find(&mut self, db: &dyn HirDatabase, ty: &Type) -> Option<Vec<Expr>> {
120+
let res = self
121+
.data
116122
.iter()
117123
.find(|(t, _)| t.could_unify_with_deeply(db, ty))
118-
.map(|(t, tts)| tts.exprs(t))
124+
.map(|(t, tts)| tts.exprs(t));
125+
126+
if res.is_none() {
127+
self.types_wishlist.insert(ty.clone());
128+
}
129+
130+
res
119131
}
120132

121133
/// Same as find but automatically creates shared reference of types in the lookup
122134
///
123135
/// For example if we have type `i32` in data and we query for `&i32` it map all the type
124136
/// trees we have for `i32` with `Expr::Reference` and returns them.
125-
fn find_autoref(&self, db: &dyn HirDatabase, ty: &Type) -> Option<Vec<Expr>> {
126-
self.data
137+
fn find_autoref(&mut self, db: &dyn HirDatabase, ty: &Type) -> Option<Vec<Expr>> {
138+
let res = self
139+
.data
127140
.iter()
128141
.find(|(t, _)| t.could_unify_with_deeply(db, ty))
129142
.map(|(t, it)| it.exprs(t))
@@ -139,7 +152,13 @@ impl LookupTable {
139152
.map(|expr| Expr::Reference(Box::new(expr)))
140153
.collect()
141154
})
142-
})
155+
});
156+
157+
if res.is_none() {
158+
self.types_wishlist.insert(ty.clone());
159+
}
160+
161+
res
143162
}
144163

145164
/// Insert new type trees for type
@@ -149,7 +168,12 @@ impl LookupTable {
149168
/// but they clearly do not unify themselves.
150169
fn insert(&mut self, ty: Type, exprs: impl Iterator<Item = Expr>) {
151170
match self.data.get_mut(&ty) {
152-
Some(it) => it.extend_with_threshold(self.many_threshold, exprs),
171+
Some(it) => {
172+
it.extend_with_threshold(self.many_threshold, exprs);
173+
if it.is_many() {
174+
self.types_wishlist.remove(&ty);
175+
}
176+
}
153177
None => {
154178
self.data.insert(ty.clone(), AlternativeExprs::new(self.many_threshold, exprs));
155179
for it in self.new_types.values_mut() {
@@ -206,8 +230,8 @@ impl LookupTable {
206230
}
207231

208232
/// Types queried but not found
209-
fn take_types_wishlist(&mut self) -> FxHashSet<Type> {
210-
std::mem::take(&mut self.types_wishlist)
233+
fn types_wishlist(&mut self) -> &FxHashSet<Type> {
234+
&self.types_wishlist
211235
}
212236
}
213237

@@ -272,7 +296,7 @@ pub fn term_search<DB: HirDatabase>(ctx: &TermSearchCtx<'_, DB>) -> Vec<Expr> {
272296
defs.insert(def);
273297
});
274298

275-
let mut lookup = LookupTable::new(ctx.config.many_alternatives_threshold);
299+
let mut lookup = LookupTable::new(ctx.config.many_alternatives_threshold, ctx.goal.clone());
276300

277301
// Try trivial tactic first, also populates lookup table
278302
let mut solutions: Vec<Expr> = tactics::trivial(ctx, &defs, &mut lookup).collect();

crates/hir/src/term_search/expr.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,8 @@ pub enum Expr {
138138
Variant { variant: Variant, generics: Vec<Type>, params: Vec<Expr> },
139139
/// Struct construction
140140
Struct { strukt: Struct, generics: Vec<Type>, params: Vec<Expr> },
141+
/// Tuple construction
142+
Tuple { ty: Type, params: Vec<Expr> },
141143
/// Struct field access
142144
Field { expr: Box<Expr>, field: Field },
143145
/// Passing type as reference (with `&`)
@@ -366,6 +368,18 @@ impl Expr {
366368
let prefix = mod_item_path_str(sema_scope, &ModuleDef::Adt(Adt::Struct(*strukt)))?;
367369
Ok(format!("{prefix}{inner}"))
368370
}
371+
Expr::Tuple { params, .. } => {
372+
let args = params
373+
.iter()
374+
.map(|a| {
375+
a.gen_source_code(sema_scope, many_formatter, prefer_no_std, prefer_prelude)
376+
})
377+
.collect::<Result<Vec<String>, DisplaySourceCodeError>>()?
378+
.into_iter()
379+
.join(", ");
380+
let res = format!("({args})");
381+
Ok(res)
382+
}
369383
Expr::Field { expr, field } => {
370384
if expr.contains_many_in_illegal_pos() {
371385
return Ok(many_formatter(&expr.ty(db)));
@@ -420,6 +434,7 @@ impl Expr {
420434
Expr::Struct { strukt, generics, .. } => {
421435
Adt::from(*strukt).ty_with_args(db, generics.iter().cloned())
422436
}
437+
Expr::Tuple { ty, .. } => ty.clone(),
423438
Expr::Field { expr, field } => field.ty_with_args(db, expr.ty(db).type_arguments()),
424439
Expr::Reference(it) => it.ty(db),
425440
Expr::Many(ty) => ty.clone(),

0 commit comments

Comments
 (0)