aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2019-08-25 10:58:54 +0100
committerGitHub <[email protected]>2019-08-25 10:58:54 +0100
commitcd433ed194f7d3570c2bee2e5ac01917513e8aa3 (patch)
tree9e5c2c98cd6b2101e31d6ed9b2f6c0f62fb16926 /crates/ra_hir/src
parent866b41ddd86cbe9c3e8d9cb2896477bab060a044 (diff)
parent14a23d1bde8493df9e5196973132144060a61709 (diff)
Merge #1734
1734: Strip indents and empty lines in check_apply_diagnostic_fix_from_position r=matklad a=matklad Co-authored-by: Phil Ellison <[email protected]>
Diffstat (limited to 'crates/ra_hir/src')
-rw-r--r--crates/ra_hir/src/diagnostics.rs28
-rw-r--r--crates/ra_hir/src/expr/validation.rs53
-rw-r--r--crates/ra_hir/src/name.rs2
-rw-r--r--crates/ra_hir/src/ty/infer.rs19
4 files changed, 98 insertions, 4 deletions
diff --git a/crates/ra_hir/src/diagnostics.rs b/crates/ra_hir/src/diagnostics.rs
index 301109cb8..475dd5766 100644
--- a/crates/ra_hir/src/diagnostics.rs
+++ b/crates/ra_hir/src/diagnostics.rs
@@ -143,3 +143,31 @@ impl AstDiagnostic for MissingFields {
143 ast::RecordFieldList::cast(node).unwrap() 143 ast::RecordFieldList::cast(node).unwrap()
144 } 144 }
145} 145}
146
147#[derive(Debug)]
148pub struct MissingOkInTailExpr {
149 pub file: HirFileId,
150 pub expr: AstPtr<ast::Expr>,
151}
152
153impl Diagnostic for MissingOkInTailExpr {
154 fn message(&self) -> String {
155 "wrap return expression in Ok".to_string()
156 }
157 fn source(&self) -> Source<SyntaxNodePtr> {
158 Source { file_id: self.file, ast: self.expr.into() }
159 }
160 fn as_any(&self) -> &(dyn Any + Send + 'static) {
161 self
162 }
163}
164
165impl AstDiagnostic for MissingOkInTailExpr {
166 type AST = ast::Expr;
167
168 fn ast(&self, db: &impl HirDatabase) -> Self::AST {
169 let root = db.parse_or_expand(self.file).unwrap();
170 let node = self.source().ast.to_node(&root);
171 ast::Expr::cast(node).unwrap()
172 }
173}
diff --git a/crates/ra_hir/src/expr/validation.rs b/crates/ra_hir/src/expr/validation.rs
index 62f7d41f5..5d9d59ff8 100644
--- a/crates/ra_hir/src/expr/validation.rs
+++ b/crates/ra_hir/src/expr/validation.rs
@@ -6,11 +6,14 @@ 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 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,11 +32,17 @@ 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::RecordLit { path, fields, spread }) = e { 37 if let (id, Expr::RecordLit { path, fields, spread }) = e {
34 self.validate_record_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_record_literal( 48 fn validate_record_literal(
@@ -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}
diff --git a/crates/ra_hir/src/name.rs b/crates/ra_hir/src/name.rs
index 6d14eea8e..9c4822d91 100644
--- a/crates/ra_hir/src/name.rs
+++ b/crates/ra_hir/src/name.rs
@@ -120,6 +120,8 @@ pub(crate) const TRY: Name = Name::new(SmolStr::new_inline_from_ascii(3, b"Try")
120pub(crate) const OK: Name = Name::new(SmolStr::new_inline_from_ascii(2, b"Ok")); 120pub(crate) const OK: Name = Name::new(SmolStr::new_inline_from_ascii(2, b"Ok"));
121pub(crate) const FUTURE_MOD: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"future")); 121pub(crate) const FUTURE_MOD: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"future"));
122pub(crate) const FUTURE_TYPE: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"Future")); 122pub(crate) const FUTURE_TYPE: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"Future"));
123pub(crate) const RESULT_MOD: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"result"));
124pub(crate) const RESULT_TYPE: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"Result"));
123pub(crate) const OUTPUT: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"Output")); 125pub(crate) const OUTPUT: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"Output"));
124 126
125fn resolve_name(text: &SmolStr) -> SmolStr { 127fn resolve_name(text: &SmolStr) -> SmolStr {
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs
index b33de5687..d94e8154b 100644
--- a/crates/ra_hir/src/ty/infer.rs
+++ b/crates/ra_hir/src/ty/infer.rs
@@ -106,6 +106,13 @@ impl Default for BindingMode {
106 } 106 }
107} 107}
108 108
109/// A mismatch between an expected and an inferred type.
110#[derive(Clone, PartialEq, Eq, Debug, Hash)]
111pub struct TypeMismatch {
112 pub expected: Ty,
113 pub actual: Ty,
114}
115
109/// The result of type inference: A mapping from expressions and patterns to types. 116/// The result of type inference: A mapping from expressions and patterns to types.
110#[derive(Clone, PartialEq, Eq, Debug, Default)] 117#[derive(Clone, PartialEq, Eq, Debug, Default)]
111pub struct InferenceResult { 118pub struct InferenceResult {
@@ -120,6 +127,7 @@ pub struct InferenceResult {
120 diagnostics: Vec<InferenceDiagnostic>, 127 diagnostics: Vec<InferenceDiagnostic>,
121 pub(super) type_of_expr: ArenaMap<ExprId, Ty>, 128 pub(super) type_of_expr: ArenaMap<ExprId, Ty>,
122 pub(super) type_of_pat: ArenaMap<PatId, Ty>, 129 pub(super) type_of_pat: ArenaMap<PatId, Ty>,
130 pub(super) type_mismatches: ArenaMap<ExprId, TypeMismatch>,
123} 131}
124 132
125impl InferenceResult { 133impl InferenceResult {
@@ -141,6 +149,9 @@ impl InferenceResult {
141 pub fn assoc_resolutions_for_pat(&self, id: PatId) -> Option<ImplItem> { 149 pub fn assoc_resolutions_for_pat(&self, id: PatId) -> Option<ImplItem> {
142 self.assoc_resolutions.get(&id.into()).copied() 150 self.assoc_resolutions.get(&id.into()).copied()
143 } 151 }
152 pub fn type_mismatch_for_expr(&self, expr: ExprId) -> Option<&TypeMismatch> {
153 self.type_mismatches.get(expr)
154 }
144 pub(crate) fn add_diagnostics( 155 pub(crate) fn add_diagnostics(
145 &self, 156 &self,
146 db: &impl HirDatabase, 157 db: &impl HirDatabase,
@@ -1345,9 +1356,15 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
1345 }; 1356 };
1346 // use a new type variable if we got Ty::Unknown here 1357 // use a new type variable if we got Ty::Unknown here
1347 let ty = self.insert_type_vars_shallow(ty); 1358 let ty = self.insert_type_vars_shallow(ty);
1348 self.unify(&ty, &expected.ty); 1359 let could_unify = self.unify(&ty, &expected.ty);
1349 let ty = self.resolve_ty_as_possible(&mut vec![], ty); 1360 let ty = self.resolve_ty_as_possible(&mut vec![], ty);
1350 self.write_expr_ty(tgt_expr, ty.clone()); 1361 self.write_expr_ty(tgt_expr, ty.clone());
1362 if !could_unify {
1363 self.result.type_mismatches.insert(
1364 tgt_expr,
1365 TypeMismatch { expected: expected.ty.clone(), actual: ty.clone() },
1366 );
1367 }
1351 ty 1368 ty
1352 } 1369 }
1353 1370