aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_ty/src/expr.rs
diff options
context:
space:
mode:
authorBenjamin Coenen <[email protected]>2020-04-11 21:54:22 +0100
committerBenjamin Coenen <[email protected]>2020-04-11 22:45:09 +0100
commit93bfc2d05d36a47dc05a1799210327473d702dbc (patch)
treedee25e78b24b5d1b23d73ae1009bddbd060927cf /crates/ra_hir_ty/src/expr.rs
parentd42346fed61f706d68fe888631a41ea5f2752d7f (diff)
parentfd06fe7b13045185ab4e630b0044aa9d8bbcdf8a (diff)
Improve autocompletion by looking on the type and name
Signed-off-by: Benjamin Coenen <[email protected]>
Diffstat (limited to 'crates/ra_hir_ty/src/expr.rs')
-rw-r--r--crates/ra_hir_ty/src/expr.rs137
1 files changed, 95 insertions, 42 deletions
diff --git a/crates/ra_hir_ty/src/expr.rs b/crates/ra_hir_ty/src/expr.rs
index e45e9ea14..69b527f74 100644
--- a/crates/ra_hir_ty/src/expr.rs
+++ b/crates/ra_hir_ty/src/expr.rs
@@ -9,7 +9,7 @@ use rustc_hash::FxHashSet;
9 9
10use crate::{ 10use crate::{
11 db::HirDatabase, 11 db::HirDatabase,
12 diagnostics::{MissingFields, MissingMatchArms, MissingOkInTailExpr}, 12 diagnostics::{MissingFields, MissingMatchArms, MissingOkInTailExpr, MissingPatFields},
13 utils::variant_data, 13 utils::variant_data,
14 ApplicationTy, InferenceResult, Ty, TypeCtor, 14 ApplicationTy, InferenceResult, Ty, TypeCtor,
15 _match::{is_useful, MatchCheckCtx, Matrix, PatStack, Usefulness}, 15 _match::{is_useful, MatchCheckCtx, Matrix, PatStack, Usefulness},
@@ -49,39 +49,95 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
49 if let Some((variant_def, missed_fields, true)) = 49 if let Some((variant_def, missed_fields, true)) =
50 record_literal_missing_fields(db, &self.infer, id, expr) 50 record_literal_missing_fields(db, &self.infer, id, expr)
51 { 51 {
52 // XXX: only look at source_map if we do have missing fields 52 self.create_record_literal_missing_fields_diagnostic(
53 let (_, source_map) = db.body_with_source_map(self.func.into()); 53 id,
54 54 db,
55 if let Ok(source_ptr) = source_map.expr_syntax(id) { 55 variant_def,
56 if let Some(expr) = source_ptr.value.left() { 56 missed_fields,
57 let root = source_ptr.file_syntax(db.upcast()); 57 );
58 if let ast::Expr::RecordLit(record_lit) = expr.to_node(&root) {
59 if let Some(field_list) = record_lit.record_field_list() {
60 let variant_data = variant_data(db.upcast(), variant_def);
61 let missed_fields = missed_fields
62 .into_iter()
63 .map(|idx| variant_data.fields()[idx].name.clone())
64 .collect();
65 self.sink.push(MissingFields {
66 file: source_ptr.file_id,
67 field_list: AstPtr::new(&field_list),
68 missed_fields,
69 })
70 }
71 }
72 }
73 }
74 } 58 }
75 if let Expr::Match { expr, arms } = expr { 59 if let Expr::Match { expr, arms } = expr {
76 self.validate_match(id, *expr, arms, db, self.infer.clone()); 60 self.validate_match(id, *expr, arms, db, self.infer.clone());
77 } 61 }
78 } 62 }
63 for (id, pat) in body.pats.iter() {
64 if let Some((variant_def, missed_fields, true)) =
65 record_pattern_missing_fields(db, &self.infer, id, pat)
66 {
67 self.create_record_pattern_missing_fields_diagnostic(
68 id,
69 db,
70 variant_def,
71 missed_fields,
72 );
73 }
74 }
79 let body_expr = &body[body.body_expr]; 75 let body_expr = &body[body.body_expr];
80 if let Expr::Block { tail: Some(t), .. } = body_expr { 76 if let Expr::Block { tail: Some(t), .. } = body_expr {
81 self.validate_results_in_tail_expr(body.body_expr, *t, db); 77 self.validate_results_in_tail_expr(body.body_expr, *t, db);
82 } 78 }
83 } 79 }
84 80
81 fn create_record_literal_missing_fields_diagnostic(
82 &mut self,
83 id: ExprId,
84 db: &dyn HirDatabase,
85 variant_def: VariantId,
86 missed_fields: Vec<LocalStructFieldId>,
87 ) {
88 // XXX: only look at source_map if we do have missing fields
89 let (_, source_map) = db.body_with_source_map(self.func.into());
90
91 if let Ok(source_ptr) = source_map.expr_syntax(id) {
92 let root = source_ptr.file_syntax(db.upcast());
93 if let ast::Expr::RecordLit(record_lit) = &source_ptr.value.to_node(&root) {
94 if let Some(field_list) = record_lit.record_field_list() {
95 let variant_data = variant_data(db.upcast(), variant_def);
96 let missed_fields = missed_fields
97 .into_iter()
98 .map(|idx| variant_data.fields()[idx].name.clone())
99 .collect();
100 self.sink.push(MissingFields {
101 file: source_ptr.file_id,
102 field_list: AstPtr::new(&field_list),
103 missed_fields,
104 })
105 }
106 }
107 }
108 }
109
110 fn create_record_pattern_missing_fields_diagnostic(
111 &mut self,
112 id: PatId,
113 db: &dyn HirDatabase,
114 variant_def: VariantId,
115 missed_fields: Vec<LocalStructFieldId>,
116 ) {
117 // XXX: only look at source_map if we do have missing fields
118 let (_, source_map) = db.body_with_source_map(self.func.into());
119
120 if let Ok(source_ptr) = source_map.pat_syntax(id) {
121 if let Some(expr) = source_ptr.value.as_ref().left() {
122 let root = source_ptr.file_syntax(db.upcast());
123 if let ast::Pat::RecordPat(record_pat) = expr.to_node(&root) {
124 if let Some(field_list) = record_pat.record_field_pat_list() {
125 let variant_data = variant_data(db.upcast(), variant_def);
126 let missed_fields = missed_fields
127 .into_iter()
128 .map(|idx| variant_data.fields()[idx].name.clone())
129 .collect();
130 self.sink.push(MissingPatFields {
131 file: source_ptr.file_id,
132 field_list: AstPtr::new(&field_list),
133 missed_fields,
134 })
135 }
136 }
137 }
138 }
139 }
140
85 fn validate_match( 141 fn validate_match(
86 &mut self, 142 &mut self,
87 id: ExprId, 143 id: ExprId,
@@ -147,18 +203,16 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
147 } 203 }
148 204
149 if let Ok(source_ptr) = source_map.expr_syntax(id) { 205 if let Ok(source_ptr) = source_map.expr_syntax(id) {
150 if let Some(expr) = source_ptr.value.left() { 206 let root = source_ptr.file_syntax(db.upcast());
151 let root = source_ptr.file_syntax(db.upcast()); 207 if let ast::Expr::MatchExpr(match_expr) = &source_ptr.value.to_node(&root) {
152 if let ast::Expr::MatchExpr(match_expr) = expr.to_node(&root) { 208 if let (Some(match_expr), Some(arms)) =
153 if let (Some(match_expr), Some(arms)) = 209 (match_expr.expr(), match_expr.match_arm_list())
154 (match_expr.expr(), match_expr.match_arm_list()) 210 {
155 { 211 self.sink.push(MissingMatchArms {
156 self.sink.push(MissingMatchArms { 212 file: source_ptr.file_id,
157 file: source_ptr.file_id, 213 match_expr: AstPtr::new(&match_expr),
158 match_expr: AstPtr::new(&match_expr), 214 arms: AstPtr::new(&arms),
159 arms: AstPtr::new(&arms), 215 })
160 })
161 }
162 } 216 }
163 } 217 }
164 } 218 }
@@ -189,9 +243,8 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
189 let (_, source_map) = db.body_with_source_map(self.func.into()); 243 let (_, source_map) = db.body_with_source_map(self.func.into());
190 244
191 if let Ok(source_ptr) = source_map.expr_syntax(id) { 245 if let Ok(source_ptr) = source_map.expr_syntax(id) {
192 if let Some(expr) = source_ptr.value.left() { 246 self.sink
193 self.sink.push(MissingOkInTailExpr { file: source_ptr.file_id, expr }); 247 .push(MissingOkInTailExpr { file: source_ptr.file_id, expr: source_ptr.value });
194 }
195 } 248 }
196 } 249 }
197 } 250 }
@@ -232,9 +285,9 @@ pub fn record_pattern_missing_fields(
232 infer: &InferenceResult, 285 infer: &InferenceResult,
233 id: PatId, 286 id: PatId,
234 pat: &Pat, 287 pat: &Pat,
235) -> Option<(VariantId, Vec<LocalStructFieldId>)> { 288) -> Option<(VariantId, Vec<LocalStructFieldId>, /*exhaustive*/ bool)> {
236 let fields = match pat { 289 let (fields, exhaustive) = match pat {
237 Pat::Record { path: _, args } => args, 290 Pat::Record { path: _, args, ellipsis } => (args, !ellipsis),
238 _ => return None, 291 _ => return None,
239 }; 292 };
240 293
@@ -254,5 +307,5 @@ pub fn record_pattern_missing_fields(
254 if missed_fields.is_empty() { 307 if missed_fields.is_empty() {
255 return None; 308 return None;
256 } 309 }
257 Some((variant_def, missed_fields)) 310 Some((variant_def, missed_fields, exhaustive))
258} 311}