aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/expr/validation.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir/src/expr/validation.rs')
-rw-r--r--crates/ra_hir/src/expr/validation.rs137
1 files changed, 0 insertions, 137 deletions
diff --git a/crates/ra_hir/src/expr/validation.rs b/crates/ra_hir/src/expr/validation.rs
deleted file mode 100644
index 3054f1dce..000000000
--- a/crates/ra_hir/src/expr/validation.rs
+++ /dev/null
@@ -1,137 +0,0 @@
1//! FIXME: write short doc here
2
3use std::sync::Arc;
4
5use hir_def::path::known;
6use hir_expand::diagnostics::DiagnosticSink;
7use ra_syntax::ast;
8use rustc_hash::FxHashSet;
9
10use crate::{
11 db::HirDatabase,
12 diagnostics::{MissingFields, MissingOkInTailExpr},
13 expr::AstPtr,
14 ty::{ApplicationTy, InferenceResult, Ty, TypeCtor},
15 Adt, Function, Name, Path,
16};
17
18use super::{Expr, ExprId, RecordLitField};
19
20pub(crate) struct ExprValidator<'a, 'b: 'a> {
21 func: Function,
22 infer: Arc<InferenceResult>,
23 sink: &'a mut DiagnosticSink<'b>,
24}
25
26impl<'a, 'b> ExprValidator<'a, 'b> {
27 pub(crate) fn new(
28 func: Function,
29 infer: Arc<InferenceResult>,
30 sink: &'a mut DiagnosticSink<'b>,
31 ) -> ExprValidator<'a, 'b> {
32 ExprValidator { func, infer, sink }
33 }
34
35 pub(crate) fn validate_body(&mut self, db: &impl HirDatabase) {
36 let body = self.func.body(db);
37
38 for e in body.exprs() {
39 if let (id, Expr::RecordLit { path, fields, spread }) = e {
40 self.validate_record_literal(id, path, fields, *spread, db);
41 }
42 }
43
44 let body_expr = &body[body.body_expr()];
45 if let Expr::Block { statements: _, tail: Some(t) } = body_expr {
46 self.validate_results_in_tail_expr(body.body_expr(), *t, db);
47 }
48 }
49
50 fn validate_record_literal(
51 &mut self,
52 id: ExprId,
53 _path: &Option<Path>,
54 fields: &[RecordLitField],
55 spread: Option<ExprId>,
56 db: &impl HirDatabase,
57 ) {
58 if spread.is_some() {
59 return;
60 }
61
62 let struct_def = match self.infer[id].as_adt() {
63 Some((Adt::Struct(s), _)) => s,
64 _ => return,
65 };
66
67 let lit_fields: FxHashSet<_> = fields.iter().map(|f| &f.name).collect();
68 let missed_fields: Vec<Name> = struct_def
69 .fields(db)
70 .iter()
71 .filter_map(|f| {
72 let name = f.name(db);
73 if lit_fields.contains(&name) {
74 None
75 } else {
76 Some(name)
77 }
78 })
79 .collect();
80 if missed_fields.is_empty() {
81 return;
82 }
83 let source_map = self.func.body_source_map(db);
84
85 if let Some(source_ptr) = source_map.expr_syntax(id) {
86 if let Some(expr) = source_ptr.ast.a() {
87 let root = source_ptr.file_syntax(db);
88 if let ast::Expr::RecordLit(record_lit) = expr.to_node(&root) {
89 if let Some(field_list) = record_lit.record_field_list() {
90 self.sink.push(MissingFields {
91 file: source_ptr.file_id,
92 field_list: AstPtr::new(&field_list),
93 missed_fields,
94 })
95 }
96 }
97 }
98 }
99 }
100
101 fn validate_results_in_tail_expr(
102 &mut self,
103 body_id: ExprId,
104 id: ExprId,
105 db: &impl HirDatabase,
106 ) {
107 // the mismatch will be on the whole block currently
108 let mismatch = match self.infer.type_mismatch_for_expr(body_id) {
109 Some(m) => m,
110 None => return,
111 };
112
113 let std_result_path = known::std_result_result();
114
115 let resolver = self.func.resolver(db);
116 let std_result_enum = match resolver.resolve_known_enum(db, &std_result_path) {
117 Some(it) => it,
118 _ => return,
119 };
120
121 let std_result_ctor = TypeCtor::Adt(Adt::Enum(std_result_enum));
122 let params = match &mismatch.expected {
123 Ty::Apply(ApplicationTy { ctor, parameters }) if ctor == &std_result_ctor => parameters,
124 _ => return,
125 };
126
127 if params.len() == 2 && &params[0] == &mismatch.actual {
128 let source_map = self.func.body_source_map(db);
129
130 if let Some(source_ptr) = source_map.expr_syntax(id) {
131 if let Some(expr) = source_ptr.ast.a() {
132 self.sink.push(MissingOkInTailExpr { file: source_ptr.file_id, expr });
133 }
134 }
135 }
136 }
137}