Skip to content

Commit 8c0be25

Browse files
committed
Expand target for autocompletion
1 parent 868e5eb commit 8c0be25

File tree

14 files changed

+259
-289
lines changed

14 files changed

+259
-289
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ authors = ["rust-analyzer team"]
1212
[profile.dev]
1313
# Disabling debug info speeds up builds a bunch,
1414
# and we don't rely on it for debugging that much.
15-
debug = 2
15+
debug = 0
1616

1717
[profile.dev.package]
1818
# These speed up local tests.

crates/hir/src/lib.rs

Lines changed: 38 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1068,20 +1068,21 @@ impl Field {
10681068
Type::new(db, var_id, ty)
10691069
}
10701070

1071-
pub fn ty_with_generics(
1072-
&self,
1073-
db: &dyn HirDatabase,
1074-
mut generics: impl Iterator<Item = Type>,
1075-
) -> Type {
1071+
pub fn ty_with_args(&self, db: &dyn HirDatabase, generics: impl Iterator<Item = Type>) -> Type {
10761072
let var_id = self.parent.into();
10771073
let def_id: AdtId = match self.parent {
10781074
VariantDef::Struct(it) => it.id.into(),
10791075
VariantDef::Union(it) => it.id.into(),
10801076
VariantDef::Variant(it) => it.parent.id.into(),
10811077
};
1078+
let mut generics = generics.map(|it| it.ty.clone());
10821079
let substs = TyBuilder::subst_for_def(db, def_id, None)
1083-
.fill(|_| {
1084-
GenericArg::new(Interner, GenericArgData::Ty(generics.next().unwrap().ty.clone()))
1080+
.fill(|x| {
1081+
let ty = generics.next().unwrap_or_else(|| TyKind::Error.intern(Interner));
1082+
match x {
1083+
ParamKind::Type => ty.cast(Interner),
1084+
ParamKind::Const(ty) => unknown_const_as_generic(ty.clone()),
1085+
}
10851086
})
10861087
.build();
10871088
let ty = db.field_types(var_id)[self.id].clone().substitute(Interner, &substs);
@@ -1141,14 +1142,15 @@ impl Struct {
11411142
Type::from_def(db, self.id)
11421143
}
11431144

1144-
pub fn ty_with_generics(
1145-
self,
1146-
db: &dyn HirDatabase,
1147-
mut generics: impl Iterator<Item = Type>,
1148-
) -> Type {
1145+
pub fn ty_with_args(self, db: &dyn HirDatabase, generics: impl Iterator<Item = Type>) -> Type {
1146+
let mut generics = generics.map(|it| it.ty.clone());
11491147
let substs = TyBuilder::subst_for_def(db, self.id, None)
1150-
.fill(|_| {
1151-
GenericArg::new(Interner, GenericArgData::Ty(generics.next().unwrap().ty.clone()))
1148+
.fill(|x| {
1149+
let ty = generics.next().unwrap_or_else(|| TyKind::Error.intern(Interner));
1150+
match x {
1151+
ParamKind::Type => ty.cast(Interner),
1152+
ParamKind::Const(ty) => unknown_const_as_generic(ty.clone()),
1153+
}
11521154
})
11531155
.build();
11541156
let ty = db.ty(self.id.into()).substitute(Interner, &substs);
@@ -1254,16 +1256,18 @@ impl Enum {
12541256
Type::from_def(db, self.id)
12551257
}
12561258

1257-
pub fn ty_with_generics(
1258-
&self,
1259-
db: &dyn HirDatabase,
1260-
mut generics: impl Iterator<Item = Type>,
1261-
) -> Type {
1259+
pub fn ty_with_args(&self, db: &dyn HirDatabase, generics: impl Iterator<Item = Type>) -> Type {
1260+
let mut generics = generics.map(|it| it.ty.clone());
12621261
let substs = TyBuilder::subst_for_def(db, self.id, None)
1263-
.fill(|_| {
1264-
GenericArg::new(Interner, GenericArgData::Ty(generics.next().unwrap().ty.clone()))
1262+
.fill(|x| {
1263+
let ty = generics.next().unwrap_or_else(|| TyKind::Error.intern(Interner));
1264+
match x {
1265+
ParamKind::Type => ty.cast(Interner),
1266+
ParamKind::Const(ty) => unknown_const_as_generic(ty.clone()),
1267+
}
12651268
})
12661269
.build();
1270+
12671271
let ty = db.ty(self.id.into()).substitute(Interner, &substs);
12681272
Type::new(db, self.id, ty)
12691273
}
@@ -2414,11 +2418,7 @@ impl SelfParam {
24142418
Type { env: environment, ty }
24152419
}
24162420

2417-
pub fn ty_with_generics(
2418-
&self,
2419-
db: &dyn HirDatabase,
2420-
mut generics: impl Iterator<Item = Type>,
2421-
) -> Type {
2421+
pub fn ty_with_args(&self, db: &dyn HirDatabase, generics: impl Iterator<Item = Type>) -> Type {
24222422
let parent_id: GenericDefId = match self.func.lookup(db.upcast()).container {
24232423
ItemContainerId::ImplId(it) => it.into(),
24242424
ItemContainerId::TraitId(it) => it.into(),
@@ -2427,16 +2427,18 @@ impl SelfParam {
24272427
}
24282428
};
24292429

2430-
let parent_substs = TyBuilder::subst_for_def(db, parent_id, None)
2431-
.fill(|_| {
2432-
GenericArg::new(Interner, GenericArgData::Ty(generics.next().unwrap().ty.clone()))
2433-
})
2434-
.build();
2435-
let substs = TyBuilder::subst_for_def(db, self.func, Some(parent_substs))
2436-
.fill(|_| {
2437-
GenericArg::new(Interner, GenericArgData::Ty(generics.next().unwrap().ty.clone()))
2438-
})
2439-
.build();
2430+
let mut generics = generics.map(|it| it.ty.clone());
2431+
let mut filler = |x: &_| {
2432+
let ty = generics.next().unwrap_or_else(|| TyKind::Error.intern(Interner));
2433+
match x {
2434+
ParamKind::Type => ty.cast(Interner),
2435+
ParamKind::Const(ty) => unknown_const_as_generic(ty.clone()),
2436+
}
2437+
};
2438+
2439+
let parent_substs = TyBuilder::subst_for_def(db, parent_id, None).fill(&mut filler).build();
2440+
let substs =
2441+
TyBuilder::subst_for_def(db, self.func, Some(parent_substs)).fill(&mut filler).build();
24402442
let callable_sig =
24412443
db.callable_item_signature(self.func.into()).substitute(Interner, &substs);
24422444
let environment = db.trait_environment(self.func.into());

crates/hir/src/term_search/mod.rs

Lines changed: 44 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -19,48 +19,61 @@ enum NewTypesKey {
1919
StructProjection,
2020
}
2121

22+
/// Helper enum to squash big number of alternative trees into `Many` variant as there is too many
23+
/// to take into account.
2224
#[derive(Debug)]
2325
enum AlternativeTrees {
26+
/// There are few trees, so we keep track of them all
2427
Few(FxHashSet<TypeTree>),
25-
Many(Type),
28+
/// There are too many trees to keep track of
29+
Many,
2630
}
2731

2832
impl AlternativeTrees {
29-
pub fn new(
30-
threshold: usize,
31-
ty: Type,
32-
trees: impl Iterator<Item = TypeTree>,
33-
) -> AlternativeTrees {
33+
/// Construct alternative trees
34+
///
35+
/// # Arguments
36+
/// `threshold` - threshold value for many trees (more than that is many)
37+
/// `trees` - trees iterator
38+
fn new(threshold: usize, trees: impl Iterator<Item = TypeTree>) -> AlternativeTrees {
3439
let mut it = AlternativeTrees::Few(Default::default());
35-
it.extend_with_threshold(threshold, ty, trees);
40+
it.extend_with_threshold(threshold, trees);
3641
it
3742
}
3843

39-
pub fn trees(&self) -> Vec<TypeTree> {
44+
/// Get type trees stored in alternative trees (or `TypeTree::Many` in case of many)
45+
///
46+
/// # Arguments
47+
/// `ty` - Type of trees queried (this is used to give type to `TypeTree::Many`)
48+
fn trees(&self, ty: &Type) -> Vec<TypeTree> {
4049
match self {
4150
AlternativeTrees::Few(trees) => trees.iter().cloned().collect(),
42-
AlternativeTrees::Many(ty) => vec![TypeTree::Many(ty.clone())],
51+
AlternativeTrees::Many => vec![TypeTree::Many(ty.clone())],
4352
}
4453
}
4554

46-
pub fn extend_with_threshold(
55+
/// Extend alternative trees
56+
///
57+
/// # Arguments
58+
/// `threshold` - threshold value for many trees (more than that is many)
59+
/// `trees` - trees iterator
60+
fn extend_with_threshold(
4761
&mut self,
4862
threshold: usize,
49-
ty: Type,
5063
mut trees: impl Iterator<Item = TypeTree>,
5164
) {
5265
match self {
5366
AlternativeTrees::Few(tts) => {
5467
while let Some(it) = trees.next() {
5568
if tts.len() > threshold {
56-
*self = AlternativeTrees::Many(ty);
69+
*self = AlternativeTrees::Many;
5770
break;
5871
}
5972

6073
tts.insert(it);
6174
}
6275
}
63-
AlternativeTrees::Many(_) => (),
76+
AlternativeTrees::Many => (),
6477
}
6578
}
6679
}
@@ -106,7 +119,7 @@ impl LookupTable {
106119
self.data
107120
.iter()
108121
.find(|(t, _)| t.could_unify_with_deeply(db, ty))
109-
.map(|(_, tts)| tts.trees())
122+
.map(|(t, tts)| tts.trees(t))
110123
}
111124

112125
/// Same as find but automatically creates shared reference of types in the lookup
@@ -117,15 +130,15 @@ impl LookupTable {
117130
self.data
118131
.iter()
119132
.find(|(t, _)| t.could_unify_with_deeply(db, ty))
120-
.map(|(_, tts)| tts.trees())
133+
.map(|(t, tts)| tts.trees(t))
121134
.or_else(|| {
122135
self.data
123136
.iter()
124137
.find(|(t, _)| {
125138
Type::reference(t, Mutability::Shared).could_unify_with_deeply(db, &ty)
126139
})
127-
.map(|(_, tts)| {
128-
tts.trees()
140+
.map(|(t, tts)| {
141+
tts.trees(t)
129142
.into_iter()
130143
.map(|tt| TypeTree::Reference(Box::new(tt)))
131144
.collect()
@@ -140,12 +153,9 @@ impl LookupTable {
140153
/// but they clearly do not unify themselves.
141154
fn insert(&mut self, ty: Type, trees: impl Iterator<Item = TypeTree>) {
142155
match self.data.get_mut(&ty) {
143-
Some(it) => it.extend_with_threshold(self.many_threshold, ty, trees),
156+
Some(it) => it.extend_with_threshold(self.many_threshold, trees),
144157
None => {
145-
self.data.insert(
146-
ty.clone(),
147-
AlternativeTrees::new(self.many_threshold, ty.clone(), trees),
148-
);
158+
self.data.insert(ty.clone(), AlternativeTrees::new(self.many_threshold, trees));
149159
for it in self.new_types.values_mut() {
150160
it.push(ty.clone());
151161
}
@@ -206,6 +216,7 @@ impl LookupTable {
206216
}
207217

208218
/// Context for the `term_search` function
219+
#[derive(Debug)]
209220
pub struct TermSearchCtx<'a, DB: HirDatabase> {
210221
/// Semantics for the program
211222
pub sema: &'a Semantics<'a, DB>,
@@ -230,7 +241,7 @@ pub struct TermSearchConfig {
230241

231242
impl Default for TermSearchConfig {
232243
fn default() -> Self {
233-
Self { enable_borrowcheck: true, many_alternatives_threshold: 1, depth: 5 }
244+
Self { enable_borrowcheck: true, many_alternatives_threshold: 1, depth: 6 }
234245
}
235246
}
236247

@@ -239,9 +250,7 @@ impl Default for TermSearchConfig {
239250
/// Search for terms (expressions) that unify with the `goal` type.
240251
///
241252
/// # Arguments
242-
/// * `sema` - Semantics for the program
243-
/// * `scope` - Semantic scope, captures context for the term search
244-
/// * `goal` - Target / expected output type
253+
/// * `ctx` - Context for term search
245254
///
246255
/// Internally this function uses Breadth First Search to find path to `goal` type.
247256
/// The general idea is following:
@@ -258,7 +267,7 @@ impl Default for TermSearchConfig {
258267
/// Note that there are usually more ways we can get to the `goal` type but some are discarded to
259268
/// reduce the memory consumption. It is also unlikely anyone is willing ti browse through
260269
/// thousands of possible responses so we currently take first 10 from every tactic.
261-
pub fn term_search<DB: HirDatabase>(ctx: TermSearchCtx<'_, DB>) -> Vec<TypeTree> {
270+
pub fn term_search<DB: HirDatabase>(ctx: &TermSearchCtx<'_, DB>) -> Vec<TypeTree> {
262271
let module = ctx.scope.module();
263272
let mut defs = FxHashSet::default();
264273
defs.insert(ScopeDef::ModuleDef(ModuleDef::Module(module)));
@@ -270,33 +279,24 @@ pub fn term_search<DB: HirDatabase>(ctx: TermSearchCtx<'_, DB>) -> Vec<TypeTree>
270279
let mut lookup = LookupTable::new();
271280

272281
// Try trivial tactic first, also populates lookup table
273-
let mut solutions: Vec<TypeTree> = tactics::trivial(&ctx, &defs, &mut lookup).collect();
282+
let mut solutions: Vec<TypeTree> = tactics::trivial(ctx, &defs, &mut lookup).collect();
274283
// Use well known types tactic before iterations as it does not depend on other tactics
275-
solutions.extend(tactics::famous_types(&ctx, &defs, &mut lookup));
276-
277-
let mut solution_found = !solutions.is_empty();
284+
solutions.extend(tactics::famous_types(ctx, &defs, &mut lookup));
278285

279286
for _ in 0..ctx.config.depth {
280287
lookup.new_round();
281288

282-
solutions.extend(tactics::type_constructor(&ctx, &defs, &mut lookup));
283-
solutions.extend(tactics::free_function(&ctx, &defs, &mut lookup));
284-
solutions.extend(tactics::impl_method(&ctx, &defs, &mut lookup));
285-
solutions.extend(tactics::struct_projection(&ctx, &defs, &mut lookup));
286-
solutions.extend(tactics::impl_static_method(&ctx, &defs, &mut lookup));
287-
288-
// Break after 1 round after successful solution
289-
if solution_found {
290-
break;
291-
}
292-
293-
solution_found = !solutions.is_empty();
289+
solutions.extend(tactics::type_constructor(ctx, &defs, &mut lookup));
290+
solutions.extend(tactics::free_function(ctx, &defs, &mut lookup));
291+
solutions.extend(tactics::impl_method(ctx, &defs, &mut lookup));
292+
solutions.extend(tactics::struct_projection(ctx, &defs, &mut lookup));
293+
solutions.extend(tactics::impl_static_method(ctx, &defs, &mut lookup));
294294

295295
// Discard not interesting `ScopeDef`s for speedup
296296
for def in lookup.exhausted_scopedefs() {
297297
defs.remove(def);
298298
}
299299
}
300300

301-
solutions.into_iter().unique().collect()
301+
solutions.into_iter().filter(|it| !it.is_many()).unique().collect()
302302
}

crates/hir/src/term_search/tactics.rs

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ pub(super) fn type_constructor<'a, DB: HirDatabase>(
160160
})
161161
.collect();
162162

163-
let enum_ty = parent_enum.ty_with_generics(db, generics.iter().cloned());
163+
let enum_ty = parent_enum.ty_with_args(db, generics.iter().cloned());
164164

165165
// Allow types with generics only if they take us straight to goal for
166166
// performance reasons
@@ -177,9 +177,7 @@ pub(super) fn type_constructor<'a, DB: HirDatabase>(
177177
let param_trees: Vec<Vec<TypeTree>> = variant
178178
.fields(db)
179179
.into_iter()
180-
.map(|field| {
181-
lookup.find(db, &field.ty_with_generics(db, generics.iter().cloned()))
182-
})
180+
.map(|field| lookup.find(db, &field.ty_with_args(db, generics.iter().cloned())))
183181
.collect::<Option<_>>()?;
184182

185183
// Note that we need special case for 0 param constructors because of multi cartesian
@@ -280,7 +278,7 @@ pub(super) fn type_constructor<'a, DB: HirDatabase>(
280278
None => g.next().expect("Missing type param"),
281279
})
282280
.collect();
283-
let struct_ty = it.ty_with_generics(db, generics.iter().cloned());
281+
let struct_ty = it.ty_with_args(db, generics.iter().cloned());
284282

285283
// Allow types with generics only if they take us straight to goal for
286284
// performance reasons
@@ -578,7 +576,7 @@ pub(super) fn impl_method<'a, DB: HirDatabase>(
578576
let self_ty = it
579577
.self_param(db)
580578
.expect("No self param")
581-
.ty_with_generics(db, ty.type_arguments().chain(generics.iter().cloned()));
579+
.ty_with_args(db, ty.type_arguments().chain(generics.iter().cloned()));
582580

583581
// Ignore functions that have different self type
584582
if !self_ty.autoderef(db).any(|s_ty| ty == s_ty) {
@@ -600,7 +598,16 @@ pub(super) fn impl_method<'a, DB: HirDatabase>(
600598
let fn_trees: Vec<TypeTree> = std::iter::once(target_type_trees)
601599
.chain(param_trees.into_iter())
602600
.multi_cartesian_product()
603-
.map(|params| TypeTree::Function { func: it, generics: Vec::new(), params })
601+
.map(|params| {
602+
let mut params = params.into_iter();
603+
let target = Box::new(params.next().unwrap());
604+
TypeTree::Method {
605+
func: it,
606+
generics: generics.clone(),
607+
target,
608+
params: params.collect(),
609+
}
610+
})
604611
.collect();
605612

606613
lookup.insert(ret_ty.clone(), fn_trees.iter().cloned());
@@ -821,7 +828,6 @@ pub(super) fn impl_static_method<'a, DB: HirDatabase>(
821828
.map(|params| TypeTree::Function {
822829
func: it,
823830
generics: generics.clone(),
824-
825831
params,
826832
})
827833
.collect()

0 commit comments

Comments
 (0)