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.rs56
1 files changed, 54 insertions, 2 deletions
diff --git a/crates/ra_hir/src/expr/validation.rs b/crates/ra_hir/src/expr/validation.rs
index 62f7d41f5..f5e641557 100644
--- a/crates/ra_hir/src/expr/validation.rs
+++ b/crates/ra_hir/src/expr/validation.rs
@@ -6,11 +6,12 @@ use ra_syntax::ast::{AstNode, RecordLit};
6use super::{Expr, ExprId, RecordLitField}; 6use super::{Expr, ExprId, RecordLitField};
7use crate::{ 7use crate::{
8 adt::AdtDef, 8 adt::AdtDef,
9 diagnostics::{DiagnosticSink, MissingFields}, 9 diagnostics::{DiagnosticSink, MissingFields, MissingOkInTailExpr},
10 expr::AstPtr, 10 expr::AstPtr,
11 ty::InferenceResult, 11 ty::{InferenceResult, Ty, TypeCtor},
12 Function, HasSource, HirDatabase, Name, Path, 12 Function, HasSource, HirDatabase, Name, Path,
13}; 13};
14use ra_syntax::ast;
14 15
15pub(crate) struct ExprValidator<'a, 'b: 'a> { 16pub(crate) struct ExprValidator<'a, 'b: 'a> {
16 func: Function, 17 func: Function,
@@ -29,11 +30,23 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
29 30
30 pub(crate) fn validate_body(&mut self, db: &impl HirDatabase) { 31 pub(crate) fn validate_body(&mut self, db: &impl HirDatabase) {
31 let body = self.func.body(db); 32 let body = self.func.body(db);
33
34 // The final expr in the function body is the whole body,
35 // so the expression being returned is the penultimate expr.
36 let mut penultimate_expr = None;
37 let mut final_expr = None;
38
32 for e in body.exprs() { 39 for e in body.exprs() {
40 penultimate_expr = final_expr;
41 final_expr = Some(e);
42
33 if let (id, Expr::RecordLit { path, fields, spread }) = e { 43 if let (id, Expr::RecordLit { path, fields, spread }) = e {
34 self.validate_record_literal(id, path, fields, *spread, db); 44 self.validate_record_literal(id, path, fields, *spread, db);
35 } 45 }
36 } 46 }
47 if let Some(e) = penultimate_expr {
48 self.validate_results_in_tail_expr(e.0, db);
49 }
37 } 50 }
38 51
39 fn validate_record_literal( 52 fn validate_record_literal(
@@ -87,4 +100,43 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
87 }) 100 })
88 } 101 }
89 } 102 }
103
104 fn validate_results_in_tail_expr(&mut self, id: ExprId, db: &impl HirDatabase) {
105 let expr_ty = &self.infer[id];
106 let func_ty = self.func.ty(db);
107 let func_sig = func_ty.callable_sig(db).unwrap();
108 let ret = func_sig.ret();
109 let ret = match ret {
110 Ty::Apply(t) => t,
111 _ => return,
112 };
113 let ret_enum = match ret.ctor {
114 TypeCtor::Adt(AdtDef::Enum(e)) => e,
115 _ => return,
116 };
117 let enum_name = ret_enum.name(db);
118 if enum_name.is_none() || enum_name.unwrap().to_string() != "Result" {
119 return;
120 }
121 let params = &ret.parameters;
122 if params.len() == 2 && &params[0] == expr_ty {
123 let source_map = self.func.body_source_map(db);
124 let file_id = self.func.source(db).file_id;
125 let parse = db.parse(file_id.original_file(db));
126 let source_file = parse.tree();
127 let expr_syntax = source_map.expr_syntax(id);
128 if expr_syntax.is_none() {
129 return;
130 }
131 let expr_syntax = expr_syntax.unwrap();
132 let node = expr_syntax.to_node(source_file.syntax());
133 let ast = ast::Expr::cast(node);
134 if ast.is_none() {
135 return;
136 }
137 let ast = ast.unwrap();
138
139 self.sink.push(MissingOkInTailExpr { file: file_id, expr: AstPtr::new(&ast) });
140 }
141 }
90} 142}