diff options
Diffstat (limited to 'crates/ra_hir')
-rw-r--r-- | crates/ra_hir/src/code_model.rs | 4 | ||||
-rw-r--r-- | crates/ra_hir/src/diagnostics.rs | 36 | ||||
-rw-r--r-- | crates/ra_hir/src/expr.rs | 43 | ||||
-rw-r--r-- | crates/ra_hir/src/expr/validation.rs | 69 | ||||
-rw-r--r-- | crates/ra_hir/src/name.rs | 2 | ||||
-rw-r--r-- | crates/ra_hir/src/source_binder.rs | 8 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/infer.rs | 31 |
7 files changed, 144 insertions, 49 deletions
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index 89fc1d1a1..66a58efed 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs | |||
@@ -318,8 +318,8 @@ pub struct StructField { | |||
318 | 318 | ||
319 | #[derive(Debug)] | 319 | #[derive(Debug)] |
320 | pub enum FieldSource { | 320 | pub enum FieldSource { |
321 | Named(ast::NamedFieldDef), | 321 | Named(ast::RecordFieldDef), |
322 | Pos(ast::PosFieldDef), | 322 | Pos(ast::TupleFieldDef), |
323 | } | 323 | } |
324 | 324 | ||
325 | impl StructField { | 325 | impl StructField { |
diff --git a/crates/ra_hir/src/diagnostics.rs b/crates/ra_hir/src/diagnostics.rs index f6240830f..475dd5766 100644 --- a/crates/ra_hir/src/diagnostics.rs +++ b/crates/ra_hir/src/diagnostics.rs | |||
@@ -79,7 +79,7 @@ impl<'a> DiagnosticSink<'a> { | |||
79 | #[derive(Debug)] | 79 | #[derive(Debug)] |
80 | pub struct NoSuchField { | 80 | pub struct NoSuchField { |
81 | pub file: HirFileId, | 81 | pub file: HirFileId, |
82 | pub field: AstPtr<ast::NamedField>, | 82 | pub field: AstPtr<ast::RecordField>, |
83 | } | 83 | } |
84 | 84 | ||
85 | impl Diagnostic for NoSuchField { | 85 | impl Diagnostic for NoSuchField { |
@@ -118,7 +118,7 @@ impl Diagnostic for UnresolvedModule { | |||
118 | #[derive(Debug)] | 118 | #[derive(Debug)] |
119 | pub struct MissingFields { | 119 | pub struct MissingFields { |
120 | pub file: HirFileId, | 120 | pub file: HirFileId, |
121 | pub field_list: AstPtr<ast::NamedFieldList>, | 121 | pub field_list: AstPtr<ast::RecordFieldList>, |
122 | pub missed_fields: Vec<Name>, | 122 | pub missed_fields: Vec<Name>, |
123 | } | 123 | } |
124 | 124 | ||
@@ -135,11 +135,39 @@ impl Diagnostic for MissingFields { | |||
135 | } | 135 | } |
136 | 136 | ||
137 | impl AstDiagnostic for MissingFields { | 137 | impl AstDiagnostic for MissingFields { |
138 | type AST = ast::NamedFieldList; | 138 | type AST = ast::RecordFieldList; |
139 | 139 | ||
140 | fn ast(&self, db: &impl HirDatabase) -> Self::AST { | 140 | fn ast(&self, db: &impl HirDatabase) -> Self::AST { |
141 | let root = db.parse_or_expand(self.source().file_id).unwrap(); | 141 | let root = db.parse_or_expand(self.source().file_id).unwrap(); |
142 | let node = self.source().ast.to_node(&root); | 142 | let node = self.source().ast.to_node(&root); |
143 | ast::NamedFieldList::cast(node).unwrap() | 143 | ast::RecordFieldList::cast(node).unwrap() |
144 | } | ||
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() | ||
144 | } | 172 | } |
145 | } | 173 | } |
diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs index 328d635d4..7cdc7555c 100644 --- a/crates/ra_hir/src/expr.rs +++ b/crates/ra_hir/src/expr.rs | |||
@@ -60,7 +60,7 @@ pub struct BodySourceMap { | |||
60 | expr_map_back: ArenaMap<ExprId, SyntaxNodePtr>, | 60 | expr_map_back: ArenaMap<ExprId, SyntaxNodePtr>, |
61 | pat_map: FxHashMap<PatPtr, PatId>, | 61 | pat_map: FxHashMap<PatPtr, PatId>, |
62 | pat_map_back: ArenaMap<PatId, PatPtr>, | 62 | pat_map_back: ArenaMap<PatId, PatPtr>, |
63 | field_map: FxHashMap<(ExprId, usize), AstPtr<ast::NamedField>>, | 63 | field_map: FxHashMap<(ExprId, usize), AstPtr<ast::RecordField>>, |
64 | } | 64 | } |
65 | 65 | ||
66 | type PatPtr = Either<AstPtr<ast::Pat>, AstPtr<ast::SelfParam>>; | 66 | type PatPtr = Either<AstPtr<ast::Pat>, AstPtr<ast::SelfParam>>; |
@@ -148,7 +148,7 @@ impl BodySourceMap { | |||
148 | self.pat_map.get(&Either::A(AstPtr::new(node))).cloned() | 148 | self.pat_map.get(&Either::A(AstPtr::new(node))).cloned() |
149 | } | 149 | } |
150 | 150 | ||
151 | pub(crate) fn field_syntax(&self, expr: ExprId, field: usize) -> AstPtr<ast::NamedField> { | 151 | pub(crate) fn field_syntax(&self, expr: ExprId, field: usize) -> AstPtr<ast::RecordField> { |
152 | self.field_map[&(expr, field)] | 152 | self.field_map[&(expr, field)] |
153 | } | 153 | } |
154 | } | 154 | } |
@@ -210,9 +210,9 @@ pub enum Expr { | |||
210 | Return { | 210 | Return { |
211 | expr: Option<ExprId>, | 211 | expr: Option<ExprId>, |
212 | }, | 212 | }, |
213 | StructLit { | 213 | RecordLit { |
214 | path: Option<Path>, | 214 | path: Option<Path>, |
215 | fields: Vec<StructLitField>, | 215 | fields: Vec<RecordLitField>, |
216 | spread: Option<ExprId>, | 216 | spread: Option<ExprId>, |
217 | }, | 217 | }, |
218 | Field { | 218 | Field { |
@@ -316,7 +316,7 @@ pub struct MatchArm { | |||
316 | } | 316 | } |
317 | 317 | ||
318 | #[derive(Debug, Clone, Eq, PartialEq)] | 318 | #[derive(Debug, Clone, Eq, PartialEq)] |
319 | pub struct StructLitField { | 319 | pub struct RecordLitField { |
320 | pub name: Name, | 320 | pub name: Name, |
321 | pub expr: ExprId, | 321 | pub expr: ExprId, |
322 | } | 322 | } |
@@ -388,7 +388,7 @@ impl Expr { | |||
388 | f(*expr); | 388 | f(*expr); |
389 | } | 389 | } |
390 | } | 390 | } |
391 | Expr::StructLit { fields, spread, .. } => { | 391 | Expr::RecordLit { fields, spread, .. } => { |
392 | for field in fields { | 392 | for field in fields { |
393 | f(field.expr); | 393 | f(field.expr); |
394 | } | 394 | } |
@@ -474,7 +474,7 @@ impl BindingAnnotation { | |||
474 | } | 474 | } |
475 | 475 | ||
476 | #[derive(Debug, Clone, Eq, PartialEq)] | 476 | #[derive(Debug, Clone, Eq, PartialEq)] |
477 | pub struct FieldPat { | 477 | pub struct RecordFieldPat { |
478 | pub(crate) name: Name, | 478 | pub(crate) name: Name, |
479 | pub(crate) pat: PatId, | 479 | pub(crate) pat: PatId, |
480 | } | 480 | } |
@@ -487,7 +487,7 @@ pub enum Pat { | |||
487 | Tuple(Vec<PatId>), | 487 | Tuple(Vec<PatId>), |
488 | Struct { | 488 | Struct { |
489 | path: Option<Path>, | 489 | path: Option<Path>, |
490 | args: Vec<FieldPat>, | 490 | args: Vec<RecordFieldPat>, |
491 | // FIXME: 'ellipsis' option | 491 | // FIXME: 'ellipsis' option |
492 | }, | 492 | }, |
493 | Range { | 493 | Range { |
@@ -746,14 +746,14 @@ where | |||
746 | let expr = e.expr().map(|e| self.collect_expr(e)); | 746 | let expr = e.expr().map(|e| self.collect_expr(e)); |
747 | self.alloc_expr(Expr::Return { expr }, syntax_ptr) | 747 | self.alloc_expr(Expr::Return { expr }, syntax_ptr) |
748 | } | 748 | } |
749 | ast::Expr::StructLit(e) => { | 749 | ast::Expr::RecordLit(e) => { |
750 | let path = e.path().and_then(Path::from_ast); | 750 | let path = e.path().and_then(Path::from_ast); |
751 | let mut field_ptrs = Vec::new(); | 751 | let mut field_ptrs = Vec::new(); |
752 | let struct_lit = if let Some(nfl) = e.named_field_list() { | 752 | let record_lit = if let Some(nfl) = e.record_field_list() { |
753 | let fields = nfl | 753 | let fields = nfl |
754 | .fields() | 754 | .fields() |
755 | .inspect(|field| field_ptrs.push(AstPtr::new(field))) | 755 | .inspect(|field| field_ptrs.push(AstPtr::new(field))) |
756 | .map(|field| StructLitField { | 756 | .map(|field| RecordLitField { |
757 | name: field | 757 | name: field |
758 | .name_ref() | 758 | .name_ref() |
759 | .map(|nr| nr.as_name()) | 759 | .map(|nr| nr.as_name()) |
@@ -776,12 +776,12 @@ where | |||
776 | }) | 776 | }) |
777 | .collect(); | 777 | .collect(); |
778 | let spread = nfl.spread().map(|s| self.collect_expr(s)); | 778 | let spread = nfl.spread().map(|s| self.collect_expr(s)); |
779 | Expr::StructLit { path, fields, spread } | 779 | Expr::RecordLit { path, fields, spread } |
780 | } else { | 780 | } else { |
781 | Expr::StructLit { path, fields: Vec::new(), spread: None } | 781 | Expr::RecordLit { path, fields: Vec::new(), spread: None } |
782 | }; | 782 | }; |
783 | 783 | ||
784 | let res = self.alloc_expr(struct_lit, syntax_ptr); | 784 | let res = self.alloc_expr(record_lit, syntax_ptr); |
785 | for (i, ptr) in field_ptrs.into_iter().enumerate() { | 785 | for (i, ptr) in field_ptrs.into_iter().enumerate() { |
786 | self.source_map.field_map.insert((res, i), ptr); | 786 | self.source_map.field_map.insert((res, i), ptr); |
787 | } | 787 | } |
@@ -994,25 +994,25 @@ where | |||
994 | Pat::Tuple(args) | 994 | Pat::Tuple(args) |
995 | } | 995 | } |
996 | ast::Pat::PlaceholderPat(_) => Pat::Wild, | 996 | ast::Pat::PlaceholderPat(_) => Pat::Wild, |
997 | ast::Pat::StructPat(p) => { | 997 | ast::Pat::RecordPat(p) => { |
998 | let path = p.path().and_then(Path::from_ast); | 998 | let path = p.path().and_then(Path::from_ast); |
999 | let field_pat_list = | 999 | let record_field_pat_list = |
1000 | p.field_pat_list().expect("every struct should have a field list"); | 1000 | p.record_field_pat_list().expect("every struct should have a field list"); |
1001 | let mut fields: Vec<_> = field_pat_list | 1001 | let mut fields: Vec<_> = record_field_pat_list |
1002 | .bind_pats() | 1002 | .bind_pats() |
1003 | .filter_map(|bind_pat| { | 1003 | .filter_map(|bind_pat| { |
1004 | let ast_pat = | 1004 | let ast_pat = |
1005 | ast::Pat::cast(bind_pat.syntax().clone()).expect("bind pat is a pat"); | 1005 | ast::Pat::cast(bind_pat.syntax().clone()).expect("bind pat is a pat"); |
1006 | let pat = self.collect_pat(ast_pat); | 1006 | let pat = self.collect_pat(ast_pat); |
1007 | let name = bind_pat.name()?.as_name(); | 1007 | let name = bind_pat.name()?.as_name(); |
1008 | Some(FieldPat { name, pat }) | 1008 | Some(RecordFieldPat { name, pat }) |
1009 | }) | 1009 | }) |
1010 | .collect(); | 1010 | .collect(); |
1011 | let iter = field_pat_list.field_pats().filter_map(|f| { | 1011 | let iter = record_field_pat_list.record_field_pats().filter_map(|f| { |
1012 | let ast_pat = f.pat()?; | 1012 | let ast_pat = f.pat()?; |
1013 | let pat = self.collect_pat(ast_pat); | 1013 | let pat = self.collect_pat(ast_pat); |
1014 | let name = f.name()?.as_name(); | 1014 | let name = f.name()?.as_name(); |
1015 | Some(FieldPat { name, pat }) | 1015 | Some(RecordFieldPat { name, pat }) |
1016 | }); | 1016 | }); |
1017 | fields.extend(iter); | 1017 | fields.extend(iter); |
1018 | 1018 | ||
@@ -1020,6 +1020,7 @@ where | |||
1020 | } | 1020 | } |
1021 | 1021 | ||
1022 | // FIXME: implement | 1022 | // FIXME: implement |
1023 | ast::Pat::BoxPat(_) => Pat::Missing, | ||
1023 | ast::Pat::LiteralPat(_) => Pat::Missing, | 1024 | ast::Pat::LiteralPat(_) => Pat::Missing, |
1024 | ast::Pat::SlicePat(_) | ast::Pat::RangePat(_) => Pat::Missing, | 1025 | ast::Pat::SlicePat(_) | ast::Pat::RangePat(_) => Pat::Missing, |
1025 | }; | 1026 | }; |
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 @@ | |||
1 | use rustc_hash::FxHashSet; | 1 | use rustc_hash::FxHashSet; |
2 | use std::sync::Arc; | 2 | use std::sync::Arc; |
3 | 3 | ||
4 | use ra_syntax::ast::{AstNode, StructLit}; | 4 | use ra_syntax::ast::{AstNode, RecordLit}; |
5 | 5 | ||
6 | use super::{Expr, ExprId, StructLitField}; | 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,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 && ¶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/source_binder.rs b/crates/ra_hir/src/source_binder.rs index e86716d74..56ff7da3a 100644 --- a/crates/ra_hir/src/source_binder.rs +++ b/crates/ra_hir/src/source_binder.rs | |||
@@ -278,13 +278,13 @@ impl SourceAnalyzer { | |||
278 | self.infer.as_ref()?.field_resolution(expr_id) | 278 | self.infer.as_ref()?.field_resolution(expr_id) |
279 | } | 279 | } |
280 | 280 | ||
281 | pub fn resolve_struct_literal(&self, struct_lit: &ast::StructLit) -> Option<crate::VariantDef> { | 281 | pub fn resolve_record_literal(&self, record_lit: &ast::RecordLit) -> Option<crate::VariantDef> { |
282 | let expr_id = self.body_source_map.as_ref()?.node_expr(&struct_lit.clone().into())?; | 282 | let expr_id = self.body_source_map.as_ref()?.node_expr(&record_lit.clone().into())?; |
283 | self.infer.as_ref()?.variant_resolution_for_expr(expr_id) | 283 | self.infer.as_ref()?.variant_resolution_for_expr(expr_id) |
284 | } | 284 | } |
285 | 285 | ||
286 | pub fn resolve_struct_pattern(&self, struct_pat: &ast::StructPat) -> Option<crate::VariantDef> { | 286 | pub fn resolve_record_pattern(&self, record_pat: &ast::RecordPat) -> Option<crate::VariantDef> { |
287 | let pat_id = self.body_source_map.as_ref()?.node_pat(&struct_pat.clone().into())?; | 287 | let pat_id = self.body_source_map.as_ref()?.node_pat(&record_pat.clone().into())?; |
288 | self.infer.as_ref()?.variant_resolution_for_pat(pat_id) | 288 | self.infer.as_ref()?.variant_resolution_for_pat(pat_id) |
289 | } | 289 | } |
290 | 290 | ||
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index cca59538a..d94e8154b 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs | |||
@@ -37,8 +37,8 @@ use crate::{ | |||
37 | code_model::{ModuleDef::Trait, TypeAlias}, | 37 | code_model::{ModuleDef::Trait, TypeAlias}, |
38 | diagnostics::DiagnosticSink, | 38 | diagnostics::DiagnosticSink, |
39 | expr::{ | 39 | expr::{ |
40 | self, Array, BinaryOp, BindingAnnotation, Body, Expr, ExprId, FieldPat, Literal, Pat, | 40 | self, Array, BinaryOp, BindingAnnotation, Body, Expr, ExprId, Literal, Pat, PatId, |
41 | PatId, Statement, UnaryOp, | 41 | RecordFieldPat, Statement, UnaryOp, |
42 | }, | 42 | }, |
43 | generics::{GenericParams, HasGenericParams}, | 43 | generics::{GenericParams, HasGenericParams}, |
44 | name, | 44 | name, |
@@ -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, |
@@ -705,10 +716,10 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
705 | ty | 716 | ty |
706 | } | 717 | } |
707 | 718 | ||
708 | fn infer_struct_pat( | 719 | fn infer_record_pat( |
709 | &mut self, | 720 | &mut self, |
710 | path: Option<&Path>, | 721 | path: Option<&Path>, |
711 | subpats: &[FieldPat], | 722 | subpats: &[RecordFieldPat], |
712 | expected: &Ty, | 723 | expected: &Ty, |
713 | default_bm: BindingMode, | 724 | default_bm: BindingMode, |
714 | id: PatId, | 725 | id: PatId, |
@@ -800,7 +811,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
800 | self.infer_tuple_struct_pat(p.as_ref(), subpats, expected, default_bm) | 811 | self.infer_tuple_struct_pat(p.as_ref(), subpats, expected, default_bm) |
801 | } | 812 | } |
802 | Pat::Struct { path: ref p, args: ref fields } => { | 813 | Pat::Struct { path: ref p, args: ref fields } => { |
803 | self.infer_struct_pat(p.as_ref(), fields, expected, default_bm, pat) | 814 | self.infer_record_pat(p.as_ref(), fields, expected, default_bm, pat) |
804 | } | 815 | } |
805 | Pat::Path(path) => { | 816 | Pat::Path(path) => { |
806 | // FIXME use correct resolver for the surrounding expression | 817 | // FIXME use correct resolver for the surrounding expression |
@@ -1103,7 +1114,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
1103 | } | 1114 | } |
1104 | Ty::simple(TypeCtor::Never) | 1115 | Ty::simple(TypeCtor::Never) |
1105 | } | 1116 | } |
1106 | Expr::StructLit { path, fields, spread } => { | 1117 | Expr::RecordLit { path, fields, spread } => { |
1107 | let (ty, def_id) = self.resolve_variant(path.as_ref()); | 1118 | let (ty, def_id) = self.resolve_variant(path.as_ref()); |
1108 | if let Some(variant) = def_id { | 1119 | if let Some(variant) = def_id { |
1109 | self.write_variant_resolution(tgt_expr.into(), variant); | 1120 | self.write_variant_resolution(tgt_expr.into(), variant); |
@@ -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 | ||