aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEkaterina Babshukova <[email protected]>2019-07-12 17:56:18 +0100
committerEkaterina Babshukova <[email protected]>2019-07-12 18:31:49 +0100
commit2a1e11b36fe90460b139f2f6aee034f63e8252bf (patch)
tree8275d86d2d105a2bd2a5d601af9b6372a523107d
parent8bb81d7418dbc4c295d31d261441b67dba4c0f76 (diff)
complete fields in enum variants
-rw-r--r--crates/ra_hir/src/adt.rs7
-rw-r--r--crates/ra_hir/src/lib.rs2
-rw-r--r--crates/ra_hir/src/source_binder.rs5
-rw-r--r--crates/ra_hir/src/ty/infer.rs15
-rw-r--r--crates/ra_ide_api/src/completion/complete_struct_literal.rs103
5 files changed, 116 insertions, 16 deletions
diff --git a/crates/ra_hir/src/adt.rs b/crates/ra_hir/src/adt.rs
index 5a3ea5f55..8afdac801 100644
--- a/crates/ra_hir/src/adt.rs
+++ b/crates/ra_hir/src/adt.rs
@@ -185,6 +185,13 @@ pub enum VariantDef {
185impl_froms!(VariantDef: Struct, EnumVariant); 185impl_froms!(VariantDef: Struct, EnumVariant);
186 186
187impl VariantDef { 187impl VariantDef {
188 pub fn fields(self, db: &impl HirDatabase) -> Vec<StructField> {
189 match self {
190 VariantDef::Struct(it) => it.fields(db),
191 VariantDef::EnumVariant(it) => it.fields(db),
192 }
193 }
194
188 pub(crate) fn field(self, db: &impl HirDatabase, name: &Name) -> Option<StructField> { 195 pub(crate) fn field(self, db: &impl HirDatabase, name: &Name) -> Option<StructField> {
189 match self { 196 match self {
190 VariantDef::Struct(it) => it.field(db, name), 197 VariantDef::Struct(it) => it.field(db, name),
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs
index 56831ba05..55d1298cf 100644
--- a/crates/ra_hir/src/lib.rs
+++ b/crates/ra_hir/src/lib.rs
@@ -55,7 +55,7 @@ use crate::{
55}; 55};
56 56
57pub use self::{ 57pub use self::{
58 adt::AdtDef, 58 adt::{AdtDef, VariantDef},
59 either::Either, 59 either::Either,
60 expr::ExprScopes, 60 expr::ExprScopes,
61 generics::{GenericParam, GenericParams, HasGenericParams}, 61 generics::{GenericParam, GenericParams, HasGenericParams},
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs
index 573add7da..071c1bb18 100644
--- a/crates/ra_hir/src/source_binder.rs
+++ b/crates/ra_hir/src/source_binder.rs
@@ -266,6 +266,11 @@ impl SourceAnalyzer {
266 self.infer.as_ref()?.field_resolution(expr_id) 266 self.infer.as_ref()?.field_resolution(expr_id)
267 } 267 }
268 268
269 pub fn resolve_variant(&self, struct_lit: &ast::StructLit) -> Option<crate::VariantDef> {
270 let expr_id = self.body_source_map.as_ref()?.node_expr(struct_lit.into())?;
271 self.infer.as_ref()?.variant_resolution(expr_id)
272 }
273
269 pub fn resolve_macro_call( 274 pub fn resolve_macro_call(
270 &self, 275 &self,
271 db: &impl HirDatabase, 276 db: &impl HirDatabase,
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs
index 26ddf0317..5ad4f73ec 100644
--- a/crates/ra_hir/src/ty/infer.rs
+++ b/crates/ra_hir/src/ty/infer.rs
@@ -113,6 +113,7 @@ pub struct InferenceResult {
113 method_resolutions: FxHashMap<ExprId, Function>, 113 method_resolutions: FxHashMap<ExprId, Function>,
114 /// For each field access expr, records the field it resolves to. 114 /// For each field access expr, records the field it resolves to.
115 field_resolutions: FxHashMap<ExprId, StructField>, 115 field_resolutions: FxHashMap<ExprId, StructField>,
116 variant_resolutions: FxHashMap<ExprId, VariantDef>,
116 /// For each associated item record what it resolves to 117 /// For each associated item record what it resolves to
117 assoc_resolutions: FxHashMap<ExprOrPatId, ImplItem>, 118 assoc_resolutions: FxHashMap<ExprOrPatId, ImplItem>,
118 diagnostics: Vec<InferenceDiagnostic>, 119 diagnostics: Vec<InferenceDiagnostic>,
@@ -127,6 +128,9 @@ impl InferenceResult {
127 pub fn field_resolution(&self, expr: ExprId) -> Option<StructField> { 128 pub fn field_resolution(&self, expr: ExprId) -> Option<StructField> {
128 self.field_resolutions.get(&expr).copied() 129 self.field_resolutions.get(&expr).copied()
129 } 130 }
131 pub fn variant_resolution(&self, expr: ExprId) -> Option<VariantDef> {
132 self.variant_resolutions.get(&expr).copied()
133 }
130 pub fn assoc_resolutions_for_expr(&self, id: ExprId) -> Option<ImplItem> { 134 pub fn assoc_resolutions_for_expr(&self, id: ExprId) -> Option<ImplItem> {
131 self.assoc_resolutions.get(&id.into()).copied() 135 self.assoc_resolutions.get(&id.into()).copied()
132 } 136 }
@@ -170,6 +174,7 @@ struct InferenceContext<'a, D: HirDatabase> {
170 obligations: Vec<Obligation>, 174 obligations: Vec<Obligation>,
171 method_resolutions: FxHashMap<ExprId, Function>, 175 method_resolutions: FxHashMap<ExprId, Function>,
172 field_resolutions: FxHashMap<ExprId, StructField>, 176 field_resolutions: FxHashMap<ExprId, StructField>,
177 variant_resolutions: FxHashMap<ExprId, VariantDef>,
173 assoc_resolutions: FxHashMap<ExprOrPatId, ImplItem>, 178 assoc_resolutions: FxHashMap<ExprOrPatId, ImplItem>,
174 type_of_expr: ArenaMap<ExprId, Ty>, 179 type_of_expr: ArenaMap<ExprId, Ty>,
175 type_of_pat: ArenaMap<PatId, Ty>, 180 type_of_pat: ArenaMap<PatId, Ty>,
@@ -183,6 +188,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
183 InferenceContext { 188 InferenceContext {
184 method_resolutions: FxHashMap::default(), 189 method_resolutions: FxHashMap::default(),
185 field_resolutions: FxHashMap::default(), 190 field_resolutions: FxHashMap::default(),
191 variant_resolutions: FxHashMap::default(),
186 assoc_resolutions: FxHashMap::default(), 192 assoc_resolutions: FxHashMap::default(),
187 type_of_expr: ArenaMap::default(), 193 type_of_expr: ArenaMap::default(),
188 type_of_pat: ArenaMap::default(), 194 type_of_pat: ArenaMap::default(),
@@ -213,6 +219,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
213 InferenceResult { 219 InferenceResult {
214 method_resolutions: self.method_resolutions, 220 method_resolutions: self.method_resolutions,
215 field_resolutions: self.field_resolutions, 221 field_resolutions: self.field_resolutions,
222 variant_resolutions: self.variant_resolutions,
216 assoc_resolutions: self.assoc_resolutions, 223 assoc_resolutions: self.assoc_resolutions,
217 type_of_expr: expr_types, 224 type_of_expr: expr_types,
218 type_of_pat: pat_types, 225 type_of_pat: pat_types,
@@ -232,6 +239,10 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
232 self.field_resolutions.insert(expr, field); 239 self.field_resolutions.insert(expr, field);
233 } 240 }
234 241
242 fn write_variant_resolution(&mut self, expr: ExprId, variant: VariantDef) {
243 self.variant_resolutions.insert(expr, variant);
244 }
245
235 fn write_assoc_resolution(&mut self, id: ExprOrPatId, item: ImplItem) { 246 fn write_assoc_resolution(&mut self, id: ExprOrPatId, item: ImplItem) {
236 self.assoc_resolutions.insert(id, item); 247 self.assoc_resolutions.insert(id, item);
237 } 248 }
@@ -1069,6 +1080,10 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
1069 } 1080 }
1070 Expr::StructLit { path, fields, spread } => { 1081 Expr::StructLit { path, fields, spread } => {
1071 let (ty, def_id) = self.resolve_variant(path.as_ref()); 1082 let (ty, def_id) = self.resolve_variant(path.as_ref());
1083 if let Some(variant) = def_id {
1084 self.write_variant_resolution(tgt_expr, variant);
1085 }
1086
1072 let substs = ty.substs().unwrap_or_else(Substs::empty); 1087 let substs = ty.substs().unwrap_or_else(Substs::empty);
1073 for (field_idx, field) in fields.iter().enumerate() { 1088 for (field_idx, field) in fields.iter().enumerate() {
1074 let field_ty = def_id 1089 let field_ty = def_id
diff --git a/crates/ra_ide_api/src/completion/complete_struct_literal.rs b/crates/ra_ide_api/src/completion/complete_struct_literal.rs
index 35fb21113..b6216f857 100644
--- a/crates/ra_ide_api/src/completion/complete_struct_literal.rs
+++ b/crates/ra_ide_api/src/completion/complete_struct_literal.rs
@@ -1,28 +1,24 @@
1use hir::AdtDef; 1use hir::{Substs, Ty};
2 2
3use crate::completion::{CompletionContext, Completions}; 3use crate::completion::{CompletionContext, Completions};
4 4
5/// Complete fields in fields literals. 5/// Complete fields in fields literals.
6pub(super) fn complete_struct_literal(acc: &mut Completions, ctx: &CompletionContext) { 6pub(super) fn complete_struct_literal(acc: &mut Completions, ctx: &CompletionContext) {
7 let ty = match ctx.struct_lit_syntax.and_then(|it| ctx.analyzer.type_of(ctx.db, it.into())) { 7 let (ty, variant) = match ctx.struct_lit_syntax.and_then(|it| {
8 Some((ctx.analyzer.type_of(ctx.db, it.into())?, ctx.analyzer.resolve_variant(it)?))
9 }) {
8 Some(it) => it, 10 Some(it) => it,
9 None => return,
10 };
11 let (adt, substs) = match ty.as_adt() {
12 Some(res) => res,
13 _ => return, 11 _ => return,
14 }; 12 };
15 match adt {
16 AdtDef::Struct(s) => {
17 for field in s.fields(ctx.db) {
18 acc.add_field(ctx, field, substs);
19 }
20 }
21 13
22 // FIXME unions 14 let ty_substs = match ty {
23 AdtDef::Union(_) => (), 15 Ty::Apply(it) => it.parameters,
24 AdtDef::Enum(_) => (), 16 _ => Substs::empty(),
25 }; 17 };
18
19 for field in variant.fields(ctx.db) {
20 acc.add_field(ctx, field, &ty_substs);
21 }
26} 22}
27 23
28#[cfg(test)] 24#[cfg(test)]
@@ -57,4 +53,81 @@ mod tests {
57 ⋮] 53 ⋮]
58 "###); 54 "###);
59 } 55 }
56
57 #[test]
58 fn test_struct_literal_enum_variant() {
59 let completions = complete(
60 r"
61 enum E {
62 A { a: u32 }
63 }
64 fn foo() {
65 let _ = E::A { <|> }
66 }
67 ",
68 );
69 assert_debug_snapshot_matches!(completions, @r###"
70 ⋮[
71 ⋮ CompletionItem {
72 ⋮ label: "a",
73 ⋮ source_range: [119; 119),
74 ⋮ delete: [119; 119),
75 ⋮ insert: "a",
76 ⋮ kind: Field,
77 ⋮ detail: "u32",
78 ⋮ },
79 ⋮]
80 "###);
81 }
82
83 #[test]
84 fn test_struct_literal_two_structs() {
85 let completions = complete(
86 r"
87 struct A { a: u32 }
88 struct B { b: u32 }
89
90 fn foo() {
91 let _: A = B { <|> }
92 }
93 ",
94 );
95 assert_debug_snapshot_matches!(completions, @r###"
96 ⋮[
97 ⋮ CompletionItem {
98 ⋮ label: "b",
99 ⋮ source_range: [119; 119),
100 ⋮ delete: [119; 119),
101 ⋮ insert: "b",
102 ⋮ kind: Field,
103 ⋮ detail: "u32",
104 ⋮ },
105 ⋮]
106 "###);
107 }
108
109 #[test]
110 fn test_struct_literal_generic_struct() {
111 let completions = complete(
112 r"
113 struct A<T> { a: T }
114
115 fn foo() {
116 let _: A<u32> = A { <|> }
117 }
118 ",
119 );
120 assert_debug_snapshot_matches!(completions, @r###"
121 ⋮[
122 ⋮ CompletionItem {
123 ⋮ label: "a",
124 ⋮ source_range: [93; 93),
125 ⋮ delete: [93; 93),
126 ⋮ insert: "a",
127 ⋮ kind: Field,
128 ⋮ detail: "u32",
129 ⋮ },
130 ⋮]
131 "###);
132 }
60} 133}