diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2019-08-25 10:58:54 +0100 |
---|---|---|
committer | GitHub <[email protected]> | 2019-08-25 10:58:54 +0100 |
commit | cd433ed194f7d3570c2bee2e5ac01917513e8aa3 (patch) | |
tree | 9e5c2c98cd6b2101e31d6ed9b2f6c0f62fb16926 /crates/ra_hir/src | |
parent | 866b41ddd86cbe9c3e8d9cb2896477bab060a044 (diff) | |
parent | 14a23d1bde8493df9e5196973132144060a61709 (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.rs | 28 | ||||
-rw-r--r-- | crates/ra_hir/src/expr/validation.rs | 53 | ||||
-rw-r--r-- | crates/ra_hir/src/name.rs | 2 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/infer.rs | 19 |
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)] | ||
148 | pub struct MissingOkInTailExpr { | ||
149 | pub file: HirFileId, | ||
150 | pub expr: AstPtr<ast::Expr>, | ||
151 | } | ||
152 | |||
153 | impl 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 | |||
165 | impl 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}; | |||
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 | 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 | }; |
16 | use ra_syntax::ast; | ||
14 | 17 | ||
15 | pub(crate) struct ExprValidator<'a, 'b: 'a> { | 18 | pub(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 && ¶ms[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") | |||
120 | pub(crate) const OK: Name = Name::new(SmolStr::new_inline_from_ascii(2, b"Ok")); | 120 | pub(crate) const OK: Name = Name::new(SmolStr::new_inline_from_ascii(2, b"Ok")); |
121 | pub(crate) const FUTURE_MOD: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"future")); | 121 | pub(crate) const FUTURE_MOD: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"future")); |
122 | pub(crate) const FUTURE_TYPE: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"Future")); | 122 | pub(crate) const FUTURE_TYPE: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"Future")); |
123 | pub(crate) const RESULT_MOD: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"result")); | ||
124 | pub(crate) const RESULT_TYPE: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"Result")); | ||
123 | pub(crate) const OUTPUT: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"Output")); | 125 | pub(crate) const OUTPUT: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"Output")); |
124 | 126 | ||
125 | fn resolve_name(text: &SmolStr) -> SmolStr { | 127 | fn 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)] | ||
111 | pub 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)] |
111 | pub struct InferenceResult { | 118 | pub 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 | ||
125 | impl InferenceResult { | 133 | impl 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 | ||