diff options
author | Phil Ellison <[email protected]> | 2019-08-10 16:40:48 +0100 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2019-08-25 10:55:55 +0100 |
commit | d00a285fa757307bbe0f8dac9e49ac247cf9dab1 (patch) | |
tree | 7ce56753d09f6b71c1a02b3c1b4078a2dd1e02f8 /crates/ra_hir/src/expr | |
parent | fdece911fe8e2f3c22760ea22038a6d00cb70dfa (diff) |
Initial implementation of Ok-wrapping
Diffstat (limited to 'crates/ra_hir/src/expr')
-rw-r--r-- | crates/ra_hir/src/expr/validation.rs | 56 |
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}; | |||
6 | use super::{Expr, ExprId, RecordLitField}; | 6 | use super::{Expr, ExprId, RecordLitField}; |
7 | use crate::{ | 7 | use 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 | }; |
14 | use ra_syntax::ast; | ||
14 | 15 | ||
15 | pub(crate) struct ExprValidator<'a, 'b: 'a> { | 16 | pub(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 && ¶ms[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 | } |