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.rs69
1 files changed, 58 insertions, 11 deletions
diff --git a/crates/ra_hir/src/expr/validation.rs b/crates/ra_hir/src/expr/validation.rs
index 82a06ca25..5d9d59ff8 100644
--- a/crates/ra_hir/src/expr/validation.rs
+++ b/crates/ra_hir/src/expr/validation.rs
@@ -1,16 +1,19 @@
1use rustc_hash::FxHashSet; 1use rustc_hash::FxHashSet;
2use std::sync::Arc; 2use std::sync::Arc;
3 3
4use ra_syntax::ast::{AstNode, StructLit}; 4use ra_syntax::ast::{AstNode, RecordLit};
5 5
6use super::{Expr, ExprId, StructLitField}; 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 name,
12 Function, HasSource, HirDatabase, Name, Path, 12 path::{PathKind, PathSegment},
13 ty::{ApplicationTy, InferenceResult, Ty, TypeCtor},
14 Function, HasSource, HirDatabase, ModuleDef, Name, Path, PerNs, Resolution,
13}; 15};
16use ra_syntax::ast;
14 17
15pub(crate) struct ExprValidator<'a, 'b: 'a> { 18pub(crate) struct ExprValidator<'a, 'b: 'a> {
16 func: Function, 19 func: Function,
@@ -29,18 +32,24 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
29 32
30 pub(crate) fn validate_body(&mut self, db: &impl HirDatabase) { 33 pub(crate) fn validate_body(&mut self, db: &impl HirDatabase) {
31 let body = self.func.body(db); 34 let body = self.func.body(db);
35
32 for e in body.exprs() { 36 for e in body.exprs() {
33 if let (id, Expr::StructLit { path, fields, spread }) = e { 37 if let (id, Expr::RecordLit { path, fields, spread }) = e {
34 self.validate_struct_literal(id, path, fields, *spread, db); 38 self.validate_record_literal(id, path, fields, *spread, db);
35 } 39 }
36 } 40 }
41
42 let body_expr = &body[body.body_expr()];
43 if let Expr::Block { statements: _, tail: Some(t) } = body_expr {
44 self.validate_results_in_tail_expr(*t, db);
45 }
37 } 46 }
38 47
39 fn validate_struct_literal( 48 fn validate_record_literal(
40 &mut self, 49 &mut self,
41 id: ExprId, 50 id: ExprId,
42 _path: &Option<Path>, 51 _path: &Option<Path>,
43 fields: &[StructLitField], 52 fields: &[RecordLitField],
44 spread: Option<ExprId>, 53 spread: Option<ExprId>,
45 db: &impl HirDatabase, 54 db: &impl HirDatabase,
46 ) { 55 ) {
@@ -76,8 +85,8 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
76 if let Some(field_list_node) = source_map 85 if let Some(field_list_node) = source_map
77 .expr_syntax(id) 86 .expr_syntax(id)
78 .map(|ptr| ptr.to_node(source_file.syntax())) 87 .map(|ptr| ptr.to_node(source_file.syntax()))
79 .and_then(StructLit::cast) 88 .and_then(RecordLit::cast)
80 .and_then(|lit| lit.named_field_list()) 89 .and_then(|lit| lit.record_field_list())
81 { 90 {
82 let field_list_ptr = AstPtr::new(&field_list_node); 91 let field_list_ptr = AstPtr::new(&field_list_node);
83 self.sink.push(MissingFields { 92 self.sink.push(MissingFields {
@@ -87,4 +96,42 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
87 }) 96 })
88 } 97 }
89 } 98 }
99
100 fn validate_results_in_tail_expr(&mut self, id: ExprId, db: &impl HirDatabase) {
101 let mismatch = match self.infer.type_mismatch_for_expr(id) {
102 Some(m) => m,
103 None => return,
104 };
105
106 let std_result_path = Path {
107 kind: PathKind::Abs,
108 segments: vec![
109 PathSegment { name: name::STD, args_and_bindings: None },
110 PathSegment { name: name::RESULT_MOD, args_and_bindings: None },
111 PathSegment { name: name::RESULT_TYPE, args_and_bindings: None },
112 ],
113 };
114
115 let resolver = self.func.resolver(db);
116 let std_result_enum =
117 match resolver.resolve_path_segments(db, &std_result_path).into_fully_resolved() {
118 PerNs { types: Some(Resolution::Def(ModuleDef::Enum(e))), .. } => e,
119 _ => return,
120 };
121
122 let std_result_ctor = TypeCtor::Adt(AdtDef::Enum(std_result_enum));
123 let params = match &mismatch.expected {
124 Ty::Apply(ApplicationTy { ctor, parameters }) if ctor == &std_result_ctor => parameters,
125 _ => return,
126 };
127
128 if params.len() == 2 && &params[0] == &mismatch.actual {
129 let source_map = self.func.body_source_map(db);
130 let file_id = self.func.source(db).file_id;
131
132 if let Some(expr) = source_map.expr_syntax(id).and_then(|n| n.cast::<ast::Expr>()) {
133 self.sink.push(MissingOkInTailExpr { file: file_id, expr });
134 }
135 }
136 }
90} 137}