diff options
Diffstat (limited to 'crates/ra_ide')
-rw-r--r-- | crates/ra_ide/src/completion/complete_record.rs | 59 |
1 files changed, 9 insertions, 50 deletions
diff --git a/crates/ra_ide/src/completion/complete_record.rs b/crates/ra_ide/src/completion/complete_record.rs index 2352ced5f..f46bcee5c 100644 --- a/crates/ra_ide/src/completion/complete_record.rs +++ b/crates/ra_ide/src/completion/complete_record.rs | |||
@@ -1,60 +1,19 @@ | |||
1 | //! Complete fields in record literals and patterns. | 1 | //! Complete fields in record literals and patterns. |
2 | use ra_syntax::{ast, ast::NameOwner, SmolStr}; | ||
3 | |||
4 | use crate::completion::{CompletionContext, Completions}; | 2 | use crate::completion::{CompletionContext, Completions}; |
5 | 3 | ||
6 | pub(super) fn complete_record(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> { | 4 | pub(super) fn complete_record(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> { |
7 | let (ty, variant, already_present_fields) = | 5 | let missing_fields = match (ctx.record_lit_pat.as_ref(), ctx.record_lit_syntax.as_ref()) { |
8 | match (ctx.record_lit_pat.as_ref(), ctx.record_lit_syntax.as_ref()) { | 6 | (None, None) => return None, |
9 | (None, None) => return None, | 7 | (Some(_), Some(_)) => unreachable!("A record cannot be both a literal and a pattern"), |
10 | (Some(_), Some(_)) => unreachable!("A record cannot be both a literal and a pattern"), | 8 | (Some(record_pat), _) => ctx.sema.record_pattern_missing_fields(record_pat), |
11 | (Some(record_pat), _) => ( | 9 | (_, Some(record_lit)) => ctx.sema.record_literal_missing_fields(record_lit), |
12 | ctx.sema.type_of_pat(&record_pat.clone().into())?, | 10 | }; |
13 | ctx.sema.resolve_record_pattern(record_pat)?, | ||
14 | pattern_ascribed_fields(record_pat), | ||
15 | ), | ||
16 | (_, Some(record_lit)) => ( | ||
17 | ctx.sema.type_of_expr(&record_lit.clone().into())?, | ||
18 | ctx.sema.resolve_record_literal(record_lit)?, | ||
19 | literal_ascribed_fields(record_lit), | ||
20 | ), | ||
21 | }; | ||
22 | 11 | ||
23 | for (field, field_ty) in ty.variant_fields(ctx.db, variant).into_iter().filter(|(field, _)| { | 12 | for (field, ty) in missing_fields { |
24 | // FIXME: already_present_names better be `Vec<hir::Name>` | 13 | acc.add_field(ctx, field, &ty) |
25 | !already_present_fields.contains(&SmolStr::from(field.name(ctx.db).to_string())) | ||
26 | }) { | ||
27 | acc.add_field(ctx, field, &field_ty); | ||
28 | } | 14 | } |
29 | Some(()) | ||
30 | } | ||
31 | 15 | ||
32 | fn literal_ascribed_fields(record_lit: &ast::RecordLit) -> Vec<SmolStr> { | 16 | Some(()) |
33 | record_lit | ||
34 | .record_field_list() | ||
35 | .map(|field_list| field_list.fields()) | ||
36 | .map(|fields| { | ||
37 | fields | ||
38 | .into_iter() | ||
39 | .filter_map(|field| field.name_ref()) | ||
40 | .map(|name_ref| name_ref.text().clone()) | ||
41 | .collect() | ||
42 | }) | ||
43 | .unwrap_or_default() | ||
44 | } | ||
45 | |||
46 | fn pattern_ascribed_fields(record_pat: &ast::RecordPat) -> Vec<SmolStr> { | ||
47 | record_pat | ||
48 | .record_field_pat_list() | ||
49 | .map(|pat_list| { | ||
50 | pat_list | ||
51 | .record_field_pats() | ||
52 | .filter_map(|fild_pat| fild_pat.name()) | ||
53 | .chain(pat_list.bind_pats().filter_map(|bind_pat| bind_pat.name())) | ||
54 | .map(|name| name.text().clone()) | ||
55 | .collect() | ||
56 | }) | ||
57 | .unwrap_or_default() | ||
58 | } | 17 | } |
59 | 18 | ||
60 | #[cfg(test)] | 19 | #[cfg(test)] |