aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir')
-rw-r--r--crates/ra_hir/src/code_model.rs4
-rw-r--r--crates/ra_hir/src/diagnostics.rs36
-rw-r--r--crates/ra_hir/src/expr.rs43
-rw-r--r--crates/ra_hir/src/expr/validation.rs69
-rw-r--r--crates/ra_hir/src/name.rs2
-rw-r--r--crates/ra_hir/src/source_binder.rs8
-rw-r--r--crates/ra_hir/src/ty/infer.rs31
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)]
320pub enum FieldSource { 320pub enum FieldSource {
321 Named(ast::NamedFieldDef), 321 Named(ast::RecordFieldDef),
322 Pos(ast::PosFieldDef), 322 Pos(ast::TupleFieldDef),
323} 323}
324 324
325impl StructField { 325impl 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)]
80pub struct NoSuchField { 80pub 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
85impl Diagnostic for NoSuchField { 85impl Diagnostic for NoSuchField {
@@ -118,7 +118,7 @@ impl Diagnostic for UnresolvedModule {
118#[derive(Debug)] 118#[derive(Debug)]
119pub struct MissingFields { 119pub 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
137impl AstDiagnostic for MissingFields { 137impl 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)]
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()
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
66type PatPtr = Either<AstPtr<ast::Pat>, AstPtr<ast::SelfParam>>; 66type 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)]
319pub struct StructLitField { 319pub 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)]
477pub struct FieldPat { 477pub 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 @@
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}
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/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)]
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,
@@ -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