Skip to content

Commit b3c924d

Browse files
committed
Run data_constructor tactic only backwards
1 parent 9b8b6f9 commit b3c924d

File tree

4 files changed

+75
-190
lines changed

4 files changed

+75
-190
lines changed

src/tools/rust-analyzer/crates/hir/src/term_search/tactics.rs

Lines changed: 69 additions & 183 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,11 @@ use itertools::Itertools;
1717
use rustc_hash::FxHashSet;
1818

1919
use crate::{
20-
Adt, AssocItem, Enum, GenericDef, GenericParam, HasVisibility, Impl, ModuleDef, ScopeDef, Type,
21-
TypeParam, Variant,
20+
Adt, AssocItem, GenericDef, GenericParam, HasVisibility, Impl, ModuleDef, ScopeDef, Type,
21+
TypeParam,
2222
};
2323

24-
use crate::term_search::{Expr, TermSearchConfig};
24+
use crate::term_search::Expr;
2525

2626
use super::{LookupTable, NewTypesKey, TermSearchCtx};
2727

@@ -151,212 +151,101 @@ pub(super) fn assoc_const<'a, DB: HirDatabase>(
151151
/// * `should_continue` - Function that indicates when to stop iterating
152152
pub(super) fn data_constructor<'a, DB: HirDatabase>(
153153
ctx: &'a TermSearchCtx<'a, DB>,
154-
defs: &'a FxHashSet<ScopeDef>,
154+
_defs: &'a FxHashSet<ScopeDef>,
155155
lookup: &'a mut LookupTable,
156156
should_continue: &'a dyn std::ops::Fn() -> bool,
157157
) -> impl Iterator<Item = Expr> + 'a {
158158
let db = ctx.sema.db;
159159
let module = ctx.scope.module();
160-
fn variant_helper(
161-
db: &dyn HirDatabase,
162-
lookup: &mut LookupTable,
163-
should_continue: &dyn std::ops::Fn() -> bool,
164-
parent_enum: Enum,
165-
variant: Variant,
166-
config: &TermSearchConfig,
167-
) -> Vec<(Type, Vec<Expr>)> {
168-
// Ignore unstable
169-
if variant.is_unstable(db) {
170-
return Vec::new();
171-
}
172-
173-
let generics = GenericDef::from(variant.parent_enum(db));
174-
let Some(type_params) = generics
175-
.type_or_const_params(db)
176-
.into_iter()
177-
.map(|it| it.as_type_param(db))
178-
.collect::<Option<Vec<TypeParam>>>()
179-
else {
180-
// Ignore enums with const generics
181-
return Vec::new();
182-
};
183-
184-
// We currently do not check lifetime bounds so ignore all types that have something to do
185-
// with them
186-
if !generics.lifetime_params(db).is_empty() {
187-
return Vec::new();
188-
}
160+
lookup
161+
.types_wishlist()
162+
.clone()
163+
.into_iter()
164+
.chain(iter::once(ctx.goal.clone()))
165+
.filter_map(|ty| ty.as_adt().map(|adt| (adt, ty)))
166+
.filter(|_| should_continue())
167+
.filter_map(move |(adt, ty)| match adt {
168+
Adt::Struct(strukt) => {
169+
// Ignore unstable or not visible
170+
if strukt.is_unstable(db) || !strukt.is_visible_from(db, module) {
171+
return None;
172+
}
189173

190-
// Only account for stable type parameters for now, unstable params can be default
191-
// tho, for example in `Box<T, #[unstable] A: Allocator>`
192-
if type_params.iter().any(|it| it.is_unstable(db) && it.default(db).is_none()) {
193-
return Vec::new();
194-
}
174+
let generics = GenericDef::from(strukt);
195175

196-
let non_default_type_params_len =
197-
type_params.iter().filter(|it| it.default(db).is_none()).count();
198-
199-
let enum_ty_shallow = Adt::from(parent_enum).ty(db);
200-
let generic_params = lookup
201-
.types_wishlist()
202-
.clone()
203-
.into_iter()
204-
.filter(|ty| ty.could_unify_with(db, &enum_ty_shallow))
205-
.map(|it| it.type_arguments().collect::<Vec<Type>>())
206-
.chain((non_default_type_params_len == 0).then_some(Vec::new()));
207-
208-
generic_params
209-
.filter(|_| should_continue())
210-
.filter_map(move |generics| {
211-
// Insert default type params
212-
let mut g = generics.into_iter();
213-
let generics: Vec<_> = type_params
214-
.iter()
215-
.map(|it| it.default(db).or_else(|| g.next()))
216-
.collect::<Option<_>>()?;
176+
// We currently do not check lifetime bounds so ignore all types that have something to do
177+
// with them
178+
if !generics.lifetime_params(db).is_empty() {
179+
return None;
180+
}
217181

218-
let enum_ty = Adt::from(parent_enum).ty_with_args(db, generics.iter().cloned());
182+
if ty.contains_unknown() {
183+
return None;
184+
}
219185

220186
// Ignore types that have something to do with lifetimes
221-
if config.enable_borrowcheck && enum_ty.contains_reference(db) {
187+
if ctx.config.enable_borrowcheck && ty.contains_reference(db) {
222188
return None;
223189
}
190+
let fields = strukt.fields(db);
191+
// Check if all fields are visible, otherwise we cannot fill them
192+
if fields.iter().any(|it| !it.is_visible_from(db, module)) {
193+
return None;
194+
}
195+
196+
let generics: Vec<_> = ty.type_arguments().collect();
224197

225198
// Early exit if some param cannot be filled from lookup
226-
let param_exprs: Vec<Vec<Expr>> = variant
227-
.fields(db)
199+
let param_exprs: Vec<Vec<Expr>> = fields
228200
.into_iter()
229201
.map(|field| lookup.find(db, &field.ty_with_args(db, generics.iter().cloned())))
230202
.collect::<Option<_>>()?;
231203

232204
// Note that we need special case for 0 param constructors because of multi cartesian
233205
// product
234-
let variant_exprs: Vec<Expr> = if param_exprs.is_empty() {
235-
vec![Expr::Variant { variant, generics, params: Vec::new() }]
206+
let exprs: Vec<Expr> = if param_exprs.is_empty() {
207+
vec![Expr::Struct { strukt, generics, params: Vec::new() }]
236208
} else {
237209
param_exprs
238210
.into_iter()
239211
.multi_cartesian_product()
240-
.map(|params| Expr::Variant { variant, generics: generics.clone(), params })
212+
.map(|params| Expr::Struct { strukt, generics: generics.clone(), params })
241213
.collect()
242214
};
243-
lookup.insert(enum_ty.clone(), variant_exprs.iter().cloned());
244-
245-
Some((enum_ty, variant_exprs))
246-
})
247-
.collect()
248-
}
249-
defs.iter()
250-
.filter_map(move |def| match def {
251-
ScopeDef::ModuleDef(ModuleDef::Variant(it)) => {
252-
let variant_exprs = variant_helper(
253-
db,
254-
lookup,
255-
should_continue,
256-
it.parent_enum(db),
257-
*it,
258-
&ctx.config,
259-
);
260-
if variant_exprs.is_empty() {
261-
return None;
262-
}
263-
if GenericDef::from(it.parent_enum(db))
264-
.type_or_const_params(db)
265-
.into_iter()
266-
.filter_map(|it| it.as_type_param(db))
267-
.all(|it| it.default(db).is_some())
268-
{
269-
lookup.mark_fulfilled(ScopeDef::ModuleDef(ModuleDef::Variant(*it)));
270-
}
271-
Some(variant_exprs)
272-
}
273-
ScopeDef::ModuleDef(ModuleDef::Adt(Adt::Enum(enum_))) => {
274-
let exprs: Vec<(Type, Vec<Expr>)> = enum_
275-
.variants(db)
276-
.into_iter()
277-
.flat_map(|it| {
278-
variant_helper(db, lookup, should_continue, *enum_, it, &ctx.config)
279-
})
280-
.collect();
281-
282-
if exprs.is_empty() {
283-
return None;
284-
}
285-
286-
if GenericDef::from(*enum_)
287-
.type_or_const_params(db)
288-
.into_iter()
289-
.filter_map(|it| it.as_type_param(db))
290-
.all(|it| it.default(db).is_some())
291-
{
292-
lookup.mark_fulfilled(ScopeDef::ModuleDef(ModuleDef::Adt(Adt::Enum(*enum_))));
293-
}
294215

295-
Some(exprs)
216+
lookup.insert(ty.clone(), exprs.iter().cloned());
217+
Some((ty, exprs))
296218
}
297-
ScopeDef::ModuleDef(ModuleDef::Adt(Adt::Struct(it))) => {
298-
// Ignore unstable and not visible
299-
if it.is_unstable(db) || !it.is_visible_from(db, module) {
219+
Adt::Enum(enum_) => {
220+
// Ignore unstable or not visible
221+
if enum_.is_unstable(db) || !enum_.is_visible_from(db, module) {
300222
return None;
301223
}
302224

303-
let generics = GenericDef::from(*it);
304-
305-
// Ignore const params for now
306-
let type_params = generics
307-
.type_or_const_params(db)
308-
.into_iter()
309-
.map(|it| it.as_type_param(db))
310-
.collect::<Option<Vec<TypeParam>>>()?;
311-
225+
let generics = GenericDef::from(enum_);
312226
// We currently do not check lifetime bounds so ignore all types that have something to do
313227
// with them
314228
if !generics.lifetime_params(db).is_empty() {
315229
return None;
316230
}
317231

318-
// Only account for stable type parameters for now, unstable params can be default
319-
// tho, for example in `Box<T, #[unstable] A: Allocator>`
320-
if type_params.iter().any(|it| it.is_unstable(db) && it.default(db).is_none()) {
232+
if ty.contains_unknown() {
321233
return None;
322234
}
323235

324-
let non_default_type_params_len =
325-
type_params.iter().filter(|it| it.default(db).is_none()).count();
236+
// Ignore types that have something to do with lifetimes
237+
if ctx.config.enable_borrowcheck && ty.contains_reference(db) {
238+
return None;
239+
}
326240

327-
let struct_ty_shallow = Adt::from(*it).ty(db);
328-
let generic_params = lookup
329-
.types_wishlist()
330-
.clone()
241+
let generics: Vec<_> = ty.type_arguments().collect();
242+
let exprs = enum_
243+
.variants(db)
331244
.into_iter()
332-
.filter(|ty| ty.could_unify_with(db, &struct_ty_shallow))
333-
.map(|it| it.type_arguments().collect::<Vec<Type>>())
334-
.chain((non_default_type_params_len == 0).then_some(Vec::new()));
335-
336-
let exprs = generic_params
337-
.filter(|_| should_continue())
338-
.filter_map(|generics| {
339-
// Insert default type params
340-
let mut g = generics.into_iter();
341-
let generics: Vec<_> = type_params
342-
.iter()
343-
.map(|it| it.default(db).or_else(|| g.next()))
344-
.collect::<Option<_>>()?;
345-
346-
let struct_ty = Adt::from(*it).ty_with_args(db, generics.iter().cloned());
347-
348-
// Ignore types that have something to do with lifetimes
349-
if ctx.config.enable_borrowcheck && struct_ty.contains_reference(db) {
350-
return None;
351-
}
352-
let fields = it.fields(db);
353-
// Check if all fields are visible, otherwise we cannot fill them
354-
if fields.iter().any(|it| !it.is_visible_from(db, module)) {
355-
return None;
356-
}
357-
245+
.filter_map(|variant| {
358246
// Early exit if some param cannot be filled from lookup
359-
let param_exprs: Vec<Vec<Expr>> = fields
247+
let param_exprs: Vec<Vec<Expr>> = variant
248+
.fields(db)
360249
.into_iter()
361250
.map(|field| {
362251
lookup.find(db, &field.ty_with_args(db, generics.iter().cloned()))
@@ -365,36 +254,33 @@ pub(super) fn data_constructor<'a, DB: HirDatabase>(
365254

366255
// Note that we need special case for 0 param constructors because of multi cartesian
367256
// product
368-
let struct_exprs: Vec<Expr> = if param_exprs.is_empty() {
369-
vec![Expr::Struct { strukt: *it, generics, params: Vec::new() }]
257+
let variant_exprs: Vec<Expr> = if param_exprs.is_empty() {
258+
vec![Expr::Variant {
259+
variant,
260+
generics: generics.clone(),
261+
params: Vec::new(),
262+
}]
370263
} else {
371264
param_exprs
372265
.into_iter()
373266
.multi_cartesian_product()
374-
.map(|params| Expr::Struct {
375-
strukt: *it,
267+
.map(|params| Expr::Variant {
268+
variant,
376269
generics: generics.clone(),
377270
params,
378271
})
379272
.collect()
380273
};
381-
382-
if non_default_type_params_len == 0 {
383-
// Fulfilled only if there are no generic parameters
384-
lookup.mark_fulfilled(ScopeDef::ModuleDef(ModuleDef::Adt(
385-
Adt::Struct(*it),
386-
)));
387-
}
388-
lookup.insert(struct_ty.clone(), struct_exprs.iter().cloned());
389-
390-
Some((struct_ty, struct_exprs))
274+
lookup.insert(ty.clone(), variant_exprs.iter().cloned());
275+
Some(variant_exprs)
391276
})
277+
.flatten()
392278
.collect();
393-
Some(exprs)
279+
280+
Some((ty, exprs))
394281
}
395-
_ => None,
282+
Adt::Union(_) => None,
396283
})
397-
.flatten()
398284
.filter_map(|(ty, exprs)| ty.could_unify_with_deeply(db, &ctx.goal).then_some(exprs))
399285
.flatten()
400286
}

src/tools/rust-analyzer/crates/ide-assists/src/handlers/term_search.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ fn f() { let a = A { x: 1, y: true }; let b: i32 = a.x; }"#,
144144
term_search,
145145
r#"//- minicore: todo, unimplemented, option
146146
fn f() { let a: i32 = 1; let b: Option<i32> = todo$0!(); }"#,
147-
r#"fn f() { let a: i32 = 1; let b: Option<i32> = None; }"#,
147+
r#"fn f() { let a: i32 = 1; let b: Option<i32> = Some(a); }"#,
148148
)
149149
}
150150

src/tools/rust-analyzer/crates/ide-completion/src/render.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -764,6 +764,7 @@ fn main() {
764764
"#,
765765
expect![[r#"
766766
st dep::test_mod_b::Struct {…} [type_could_unify]
767+
ex dep::test_mod_b::Struct { } [type_could_unify]
767768
st Struct (use dep::test_mod_b::Struct) [type_could_unify+requires_import]
768769
fn main() []
769770
fn test(…) []
@@ -839,6 +840,7 @@ fn main() {
839840
"#,
840841
expect![[r#"
841842
ev dep::test_mod_b::Enum::variant [type_could_unify]
843+
ex dep::test_mod_b::Enum::variant [type_could_unify]
842844
en Enum (use dep::test_mod_b::Enum) [type_could_unify+requires_import]
843845
fn main() []
844846
fn test(…) []
@@ -876,6 +878,7 @@ fn main() {
876878
"#,
877879
expect![[r#"
878880
ev dep::test_mod_b::Enum::Variant [type_could_unify]
881+
ex dep::test_mod_b::Enum::Variant [type_could_unify]
879882
fn main() []
880883
fn test(…) []
881884
md dep []
@@ -1839,7 +1842,6 @@ fn f() { A { bar: b$0 }; }
18391842
fn baz() [type]
18401843
ex baz() [type]
18411844
ex bar() [type]
1842-
ex A { bar: ... }.bar [type]
18431845
st A []
18441846
fn f() []
18451847
"#]],
@@ -1978,7 +1980,6 @@ fn main() {
19781980
"#,
19791981
expect![[r#"
19801982
ex core::ops::Deref::deref(&t) (use core::ops::Deref) [type_could_unify]
1981-
ex core::ops::Deref::deref(&T(S)) (use core::ops::Deref) [type_could_unify]
19821983
lc m [local]
19831984
lc t [local]
19841985
lc &t [type+local]
@@ -2028,7 +2029,6 @@ fn main() {
20282029
"#,
20292030
expect![[r#"
20302031
ex core::ops::DerefMut::deref_mut(&mut t) (use core::ops::DerefMut) [type_could_unify]
2031-
ex core::ops::DerefMut::deref_mut(&mut T(S)) (use core::ops::DerefMut) [type_could_unify]
20322032
lc m [local]
20332033
lc t [local]
20342034
lc &mut t [type+local]
@@ -2132,7 +2132,6 @@ fn main() {
21322132
}
21332133
"#,
21342134
expect![[r#"
2135-
ex core::ops::Deref::deref(&T(S)) (use core::ops::Deref) [type_could_unify]
21362135
ex core::ops::Deref::deref(&bar()) (use core::ops::Deref) [type_could_unify]
21372136
st S []
21382137
st &S [type]

0 commit comments

Comments
 (0)