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