aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_ty
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir_ty')
-rw-r--r--crates/ra_hir_ty/Cargo.toml6
-rw-r--r--crates/ra_hir_ty/src/diagnostics.rs128
-rw-r--r--crates/ra_hir_ty/src/diagnostics/expr.rs14
-rw-r--r--crates/ra_hir_ty/src/diagnostics/match_check.rs8
-rw-r--r--crates/ra_hir_ty/src/diagnostics/unsafe_check.rs38
-rw-r--r--crates/ra_hir_ty/src/infer.rs11
-rw-r--r--crates/ra_hir_ty/src/lower.rs5
-rw-r--r--crates/ra_hir_ty/src/tests/simple.rs38
8 files changed, 141 insertions, 107 deletions
diff --git a/crates/ra_hir_ty/Cargo.toml b/crates/ra_hir_ty/Cargo.toml
index 623ce261a..83397d579 100644
--- a/crates/ra_hir_ty/Cargo.toml
+++ b/crates/ra_hir_ty/Cargo.toml
@@ -28,9 +28,9 @@ test_utils = { path = "../test_utils" }
28 28
29scoped-tls = "1" 29scoped-tls = "1"
30 30
31chalk-solve = { version = "0.19.0" } 31chalk-solve = { version = "0.21.0" }
32chalk-ir = { version = "0.19.0" } 32chalk-ir = { version = "0.21.0" }
33chalk-recursive = { version = "0.19.0" } 33chalk-recursive = { version = "0.21.0" }
34 34
35[dev-dependencies] 35[dev-dependencies]
36expect = { path = "../expect" } 36expect = { path = "../expect" }
diff --git a/crates/ra_hir_ty/src/diagnostics.rs b/crates/ra_hir_ty/src/diagnostics.rs
index 977c0525b..7ab7f79db 100644
--- a/crates/ra_hir_ty/src/diagnostics.rs
+++ b/crates/ra_hir_ty/src/diagnostics.rs
@@ -6,10 +6,10 @@ mod unsafe_check;
6use std::any::Any; 6use std::any::Any;
7 7
8use hir_def::DefWithBodyId; 8use hir_def::DefWithBodyId;
9use hir_expand::diagnostics::{AstDiagnostic, Diagnostic, DiagnosticSink}; 9use hir_expand::diagnostics::{Diagnostic, DiagnosticSink};
10use hir_expand::{db::AstDatabase, name::Name, HirFileId, InFile}; 10use hir_expand::{name::Name, HirFileId, InFile};
11use ra_prof::profile; 11use ra_prof::profile;
12use ra_syntax::{ast, AstNode, AstPtr, SyntaxNodePtr}; 12use ra_syntax::{ast, AstPtr, SyntaxNodePtr};
13use stdx::format_to; 13use stdx::format_to;
14 14
15use crate::db::HirDatabase; 15use crate::db::HirDatabase;
@@ -37,7 +37,7 @@ impl Diagnostic for NoSuchField {
37 "no such field".to_string() 37 "no such field".to_string()
38 } 38 }
39 39
40 fn source(&self) -> InFile<SyntaxNodePtr> { 40 fn display_source(&self) -> InFile<SyntaxNodePtr> {
41 InFile::new(self.file, self.field.clone().into()) 41 InFile::new(self.file, self.field.clone().into())
42 } 42 }
43 43
@@ -46,20 +46,11 @@ impl Diagnostic for NoSuchField {
46 } 46 }
47} 47}
48 48
49impl AstDiagnostic for NoSuchField {
50 type AST = ast::RecordExprField;
51
52 fn ast(&self, db: &dyn AstDatabase) -> Self::AST {
53 let root = db.parse_or_expand(self.source().file_id).unwrap();
54 let node = self.source().value.to_node(&root);
55 ast::RecordExprField::cast(node).unwrap()
56 }
57}
58
59#[derive(Debug)] 49#[derive(Debug)]
60pub struct MissingFields { 50pub struct MissingFields {
61 pub file: HirFileId, 51 pub file: HirFileId,
62 pub field_list: AstPtr<ast::RecordExprFieldList>, 52 pub field_list_parent: AstPtr<ast::RecordExpr>,
53 pub field_list_parent_path: Option<AstPtr<ast::Path>>,
63 pub missed_fields: Vec<Name>, 54 pub missed_fields: Vec<Name>,
64} 55}
65 56
@@ -71,28 +62,28 @@ impl Diagnostic for MissingFields {
71 } 62 }
72 buf 63 buf
73 } 64 }
74 fn source(&self) -> InFile<SyntaxNodePtr> { 65
75 InFile { file_id: self.file, value: self.field_list.clone().into() } 66 fn display_source(&self) -> InFile<SyntaxNodePtr> {
67 InFile {
68 file_id: self.file,
69 value: self
70 .field_list_parent_path
71 .clone()
72 .map(SyntaxNodePtr::from)
73 .unwrap_or_else(|| self.field_list_parent.clone().into()),
74 }
76 } 75 }
76
77 fn as_any(&self) -> &(dyn Any + Send + 'static) { 77 fn as_any(&self) -> &(dyn Any + Send + 'static) {
78 self 78 self
79 } 79 }
80} 80}
81 81
82impl AstDiagnostic for MissingFields {
83 type AST = ast::RecordExprFieldList;
84
85 fn ast(&self, db: &dyn AstDatabase) -> Self::AST {
86 let root = db.parse_or_expand(self.source().file_id).unwrap();
87 let node = self.source().value.to_node(&root);
88 ast::RecordExprFieldList::cast(node).unwrap()
89 }
90}
91
92#[derive(Debug)] 82#[derive(Debug)]
93pub struct MissingPatFields { 83pub struct MissingPatFields {
94 pub file: HirFileId, 84 pub file: HirFileId,
95 pub field_list: AstPtr<ast::RecordPatFieldList>, 85 pub field_list_parent: AstPtr<ast::RecordPat>,
86 pub field_list_parent_path: Option<AstPtr<ast::Path>>,
96 pub missed_fields: Vec<Name>, 87 pub missed_fields: Vec<Name>,
97} 88}
98 89
@@ -104,8 +95,15 @@ impl Diagnostic for MissingPatFields {
104 } 95 }
105 buf 96 buf
106 } 97 }
107 fn source(&self) -> InFile<SyntaxNodePtr> { 98 fn display_source(&self) -> InFile<SyntaxNodePtr> {
108 InFile { file_id: self.file, value: self.field_list.clone().into() } 99 InFile {
100 file_id: self.file,
101 value: self
102 .field_list_parent_path
103 .clone()
104 .map(SyntaxNodePtr::from)
105 .unwrap_or_else(|| self.field_list_parent.clone().into()),
106 }
109 } 107 }
110 fn as_any(&self) -> &(dyn Any + Send + 'static) { 108 fn as_any(&self) -> &(dyn Any + Send + 'static) {
111 self 109 self
@@ -123,7 +121,7 @@ impl Diagnostic for MissingMatchArms {
123 fn message(&self) -> String { 121 fn message(&self) -> String {
124 String::from("Missing match arm") 122 String::from("Missing match arm")
125 } 123 }
126 fn source(&self) -> InFile<SyntaxNodePtr> { 124 fn display_source(&self) -> InFile<SyntaxNodePtr> {
127 InFile { file_id: self.file, value: self.match_expr.clone().into() } 125 InFile { file_id: self.file, value: self.match_expr.clone().into() }
128 } 126 }
129 fn as_any(&self) -> &(dyn Any + Send + 'static) { 127 fn as_any(&self) -> &(dyn Any + Send + 'static) {
@@ -141,7 +139,7 @@ impl Diagnostic for MissingOkInTailExpr {
141 fn message(&self) -> String { 139 fn message(&self) -> String {
142 "wrap return expression in Ok".to_string() 140 "wrap return expression in Ok".to_string()
143 } 141 }
144 fn source(&self) -> InFile<SyntaxNodePtr> { 142 fn display_source(&self) -> InFile<SyntaxNodePtr> {
145 InFile { file_id: self.file, value: self.expr.clone().into() } 143 InFile { file_id: self.file, value: self.expr.clone().into() }
146 } 144 }
147 fn as_any(&self) -> &(dyn Any + Send + 'static) { 145 fn as_any(&self) -> &(dyn Any + Send + 'static) {
@@ -149,16 +147,6 @@ impl Diagnostic for MissingOkInTailExpr {
149 } 147 }
150} 148}
151 149
152impl AstDiagnostic for MissingOkInTailExpr {
153 type AST = ast::Expr;
154
155 fn ast(&self, db: &dyn AstDatabase) -> Self::AST {
156 let root = db.parse_or_expand(self.file).unwrap();
157 let node = self.source().value.to_node(&root);
158 ast::Expr::cast(node).unwrap()
159 }
160}
161
162#[derive(Debug)] 150#[derive(Debug)]
163pub struct BreakOutsideOfLoop { 151pub struct BreakOutsideOfLoop {
164 pub file: HirFileId, 152 pub file: HirFileId,
@@ -169,7 +157,7 @@ impl Diagnostic for BreakOutsideOfLoop {
169 fn message(&self) -> String { 157 fn message(&self) -> String {
170 "break outside of loop".to_string() 158 "break outside of loop".to_string()
171 } 159 }
172 fn source(&self) -> InFile<SyntaxNodePtr> { 160 fn display_source(&self) -> InFile<SyntaxNodePtr> {
173 InFile { file_id: self.file, value: self.expr.clone().into() } 161 InFile { file_id: self.file, value: self.expr.clone().into() }
174 } 162 }
175 fn as_any(&self) -> &(dyn Any + Send + 'static) { 163 fn as_any(&self) -> &(dyn Any + Send + 'static) {
@@ -177,16 +165,6 @@ impl Diagnostic for BreakOutsideOfLoop {
177 } 165 }
178} 166}
179 167
180impl AstDiagnostic for BreakOutsideOfLoop {
181 type AST = ast::Expr;
182
183 fn ast(&self, db: &dyn AstDatabase) -> Self::AST {
184 let root = db.parse_or_expand(self.file).unwrap();
185 let node = self.source().value.to_node(&root);
186 ast::Expr::cast(node).unwrap()
187 }
188}
189
190#[derive(Debug)] 168#[derive(Debug)]
191pub struct MissingUnsafe { 169pub struct MissingUnsafe {
192 pub file: HirFileId, 170 pub file: HirFileId,
@@ -197,7 +175,7 @@ impl Diagnostic for MissingUnsafe {
197 fn message(&self) -> String { 175 fn message(&self) -> String {
198 format!("This operation is unsafe and requires an unsafe function or block") 176 format!("This operation is unsafe and requires an unsafe function or block")
199 } 177 }
200 fn source(&self) -> InFile<SyntaxNodePtr> { 178 fn display_source(&self) -> InFile<SyntaxNodePtr> {
201 InFile { file_id: self.file, value: self.expr.clone().into() } 179 InFile { file_id: self.file, value: self.expr.clone().into() }
202 } 180 }
203 fn as_any(&self) -> &(dyn Any + Send + 'static) { 181 fn as_any(&self) -> &(dyn Any + Send + 'static) {
@@ -205,16 +183,6 @@ impl Diagnostic for MissingUnsafe {
205 } 183 }
206} 184}
207 185
208impl AstDiagnostic for MissingUnsafe {
209 type AST = ast::Expr;
210
211 fn ast(&self, db: &dyn AstDatabase) -> Self::AST {
212 let root = db.parse_or_expand(self.source().file_id).unwrap();
213 let node = self.source().value.to_node(&root);
214 ast::Expr::cast(node).unwrap()
215 }
216}
217
218#[derive(Debug)] 186#[derive(Debug)]
219pub struct MismatchedArgCount { 187pub struct MismatchedArgCount {
220 pub file: HirFileId, 188 pub file: HirFileId,
@@ -228,7 +196,7 @@ impl Diagnostic for MismatchedArgCount {
228 let s = if self.expected == 1 { "" } else { "s" }; 196 let s = if self.expected == 1 { "" } else { "s" };
229 format!("Expected {} argument{}, found {}", self.expected, s, self.found) 197 format!("Expected {} argument{}, found {}", self.expected, s, self.found)
230 } 198 }
231 fn source(&self) -> InFile<SyntaxNodePtr> { 199 fn display_source(&self) -> InFile<SyntaxNodePtr> {
232 InFile { file_id: self.file, value: self.call_expr.clone().into() } 200 InFile { file_id: self.file, value: self.call_expr.clone().into() }
233 } 201 }
234 fn as_any(&self) -> &(dyn Any + Send + 'static) { 202 fn as_any(&self) -> &(dyn Any + Send + 'static) {
@@ -239,19 +207,13 @@ impl Diagnostic for MismatchedArgCount {
239 } 207 }
240} 208}
241 209
242impl AstDiagnostic for MismatchedArgCount {
243 type AST = ast::CallExpr;
244 fn ast(&self, db: &dyn AstDatabase) -> Self::AST {
245 let root = db.parse_or_expand(self.source().file_id).unwrap();
246 let node = self.source().value.to_node(&root);
247 ast::CallExpr::cast(node).unwrap()
248 }
249}
250
251#[cfg(test)] 210#[cfg(test)]
252mod tests { 211mod tests {
253 use hir_def::{db::DefDatabase, AssocItemId, ModuleDefId}; 212 use hir_def::{db::DefDatabase, AssocItemId, ModuleDefId};
254 use hir_expand::diagnostics::{Diagnostic, DiagnosticSinkBuilder}; 213 use hir_expand::{
214 db::AstDatabase,
215 diagnostics::{Diagnostic, DiagnosticSinkBuilder},
216 };
255 use ra_db::{fixture::WithFixture, FileId, SourceDatabase, SourceDatabaseExt}; 217 use ra_db::{fixture::WithFixture, FileId, SourceDatabase, SourceDatabaseExt};
256 use ra_syntax::{TextRange, TextSize}; 218 use ra_syntax::{TextRange, TextSize};
257 use rustc_hash::FxHashMap; 219 use rustc_hash::FxHashMap;
@@ -296,9 +258,11 @@ mod tests {
296 258
297 let mut actual: FxHashMap<FileId, Vec<(TextRange, String)>> = FxHashMap::default(); 259 let mut actual: FxHashMap<FileId, Vec<(TextRange, String)>> = FxHashMap::default();
298 db.diagnostics(|d| { 260 db.diagnostics(|d| {
299 // FXIME: macros... 261 let src = d.display_source();
300 let file_id = d.source().file_id.original_file(&db); 262 let root = db.parse_or_expand(src.file_id).unwrap();
301 let range = d.syntax_node(&db).text_range(); 263 // FIXME: macros...
264 let file_id = src.file_id.original_file(&db);
265 let range = src.value.to_node(&root).text_range();
302 let message = d.message().to_owned(); 266 let message = d.message().to_owned();
303 actual.entry(file_id).or_default().push((range, message)); 267 actual.entry(file_id).or_default().push((range, message));
304 }); 268 });
@@ -326,8 +290,8 @@ struct S { foo: i32, bar: () }
326impl S { 290impl S {
327 fn new() -> S { 291 fn new() -> S {
328 S { 292 S {
329 //^... Missing structure fields: 293 //^ Missing structure fields:
330 //| - bar 294 //| - bar
331 foo: 92, 295 foo: 92,
332 baz: 62, 296 baz: 62,
333 //^^^^^^^ no such field 297 //^^^^^^^ no such field
@@ -448,8 +412,8 @@ impl Foo {
448struct S { foo: i32, bar: () } 412struct S { foo: i32, bar: () }
449fn baz(s: S) { 413fn baz(s: S) {
450 let S { foo: _ } = s; 414 let S { foo: _ } = s;
451 //^^^^^^^^^^ Missing structure fields: 415 //^ Missing structure fields:
452 // | - bar 416 //| - bar
453} 417}
454"#, 418"#,
455 ); 419 );
diff --git a/crates/ra_hir_ty/src/diagnostics/expr.rs b/crates/ra_hir_ty/src/diagnostics/expr.rs
index 95bbf2d95..51adcecaf 100644
--- a/crates/ra_hir_ty/src/diagnostics/expr.rs
+++ b/crates/ra_hir_ty/src/diagnostics/expr.rs
@@ -100,8 +100,8 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
100 100
101 if let Ok(source_ptr) = source_map.expr_syntax(id) { 101 if let Ok(source_ptr) = source_map.expr_syntax(id) {
102 let root = source_ptr.file_syntax(db.upcast()); 102 let root = source_ptr.file_syntax(db.upcast());
103 if let ast::Expr::RecordExpr(record_lit) = &source_ptr.value.to_node(&root) { 103 if let ast::Expr::RecordExpr(record_expr) = &source_ptr.value.to_node(&root) {
104 if let Some(field_list) = record_lit.record_expr_field_list() { 104 if let Some(_) = record_expr.record_expr_field_list() {
105 let variant_data = variant_data(db.upcast(), variant_def); 105 let variant_data = variant_data(db.upcast(), variant_def);
106 let missed_fields = missed_fields 106 let missed_fields = missed_fields
107 .into_iter() 107 .into_iter()
@@ -109,7 +109,8 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
109 .collect(); 109 .collect();
110 self.sink.push(MissingFields { 110 self.sink.push(MissingFields {
111 file: source_ptr.file_id, 111 file: source_ptr.file_id,
112 field_list: AstPtr::new(&field_list), 112 field_list_parent: AstPtr::new(&record_expr),
113 field_list_parent_path: record_expr.path().map(|path| AstPtr::new(&path)),
113 missed_fields, 114 missed_fields,
114 }) 115 })
115 } 116 }
@@ -131,7 +132,7 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
131 if let Some(expr) = source_ptr.value.as_ref().left() { 132 if let Some(expr) = source_ptr.value.as_ref().left() {
132 let root = source_ptr.file_syntax(db.upcast()); 133 let root = source_ptr.file_syntax(db.upcast());
133 if let ast::Pat::RecordPat(record_pat) = expr.to_node(&root) { 134 if let ast::Pat::RecordPat(record_pat) = expr.to_node(&root) {
134 if let Some(field_list) = record_pat.record_pat_field_list() { 135 if let Some(_) = record_pat.record_pat_field_list() {
135 let variant_data = variant_data(db.upcast(), variant_def); 136 let variant_data = variant_data(db.upcast(), variant_def);
136 let missed_fields = missed_fields 137 let missed_fields = missed_fields
137 .into_iter() 138 .into_iter()
@@ -139,7 +140,10 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
139 .collect(); 140 .collect();
140 self.sink.push(MissingPatFields { 141 self.sink.push(MissingPatFields {
141 file: source_ptr.file_id, 142 file: source_ptr.file_id,
142 field_list: AstPtr::new(&field_list), 143 field_list_parent: AstPtr::new(&record_pat),
144 field_list_parent_path: record_pat
145 .path()
146 .map(|path| AstPtr::new(&path)),
143 missed_fields, 147 missed_fields,
144 }) 148 })
145 } 149 }
diff --git a/crates/ra_hir_ty/src/diagnostics/match_check.rs b/crates/ra_hir_ty/src/diagnostics/match_check.rs
index 507edcb7d..deca244db 100644
--- a/crates/ra_hir_ty/src/diagnostics/match_check.rs
+++ b/crates/ra_hir_ty/src/diagnostics/match_check.rs
@@ -1161,15 +1161,15 @@ fn main() {
1161 //^ Missing match arm 1161 //^ Missing match arm
1162 match a { 1162 match a {
1163 Either::A { } => (), 1163 Either::A { } => (),
1164 //^^^ Missing structure fields: 1164 //^^^^^^^^^ Missing structure fields:
1165 // | - foo 1165 // | - foo
1166 Either::B => (), 1166 Either::B => (),
1167 } 1167 }
1168 match a { 1168 match a {
1169 //^ Missing match arm 1169 //^ Missing match arm
1170 Either::A { } => (), 1170 Either::A { } => (),
1171 } //^^^ Missing structure fields: 1171 } //^^^^^^^^^ Missing structure fields:
1172 // | - foo 1172 // | - foo
1173 1173
1174 match a { 1174 match a {
1175 Either::A { foo: true } => (), 1175 Either::A { foo: true } => (),
diff --git a/crates/ra_hir_ty/src/diagnostics/unsafe_check.rs b/crates/ra_hir_ty/src/diagnostics/unsafe_check.rs
index 5cc76bdce..61ffbf5d1 100644
--- a/crates/ra_hir_ty/src/diagnostics/unsafe_check.rs
+++ b/crates/ra_hir_ty/src/diagnostics/unsafe_check.rs
@@ -6,6 +6,7 @@ use std::sync::Arc;
6use hir_def::{ 6use hir_def::{
7 body::Body, 7 body::Body,
8 expr::{Expr, ExprId, UnaryOp}, 8 expr::{Expr, ExprId, UnaryOp},
9 resolver::{resolver_for_expr, ResolveValueResult, ValueNs},
9 DefWithBodyId, 10 DefWithBodyId,
10}; 11};
11use hir_expand::diagnostics::DiagnosticSink; 12use hir_expand::diagnostics::DiagnosticSink;
@@ -70,7 +71,7 @@ pub fn unsafe_expressions(
70) -> Vec<UnsafeExpr> { 71) -> Vec<UnsafeExpr> {
71 let mut unsafe_exprs = vec![]; 72 let mut unsafe_exprs = vec![];
72 let body = db.body(def); 73 let body = db.body(def);
73 walk_unsafe(&mut unsafe_exprs, db, infer, &body, body.body_expr, false); 74 walk_unsafe(&mut unsafe_exprs, db, infer, def, &body, body.body_expr, false);
74 75
75 unsafe_exprs 76 unsafe_exprs
76} 77}
@@ -79,6 +80,7 @@ fn walk_unsafe(
79 unsafe_exprs: &mut Vec<UnsafeExpr>, 80 unsafe_exprs: &mut Vec<UnsafeExpr>,
80 db: &dyn HirDatabase, 81 db: &dyn HirDatabase,
81 infer: &InferenceResult, 82 infer: &InferenceResult,
83 def: DefWithBodyId,
82 body: &Body, 84 body: &Body,
83 current: ExprId, 85 current: ExprId,
84 inside_unsafe_block: bool, 86 inside_unsafe_block: bool,
@@ -97,6 +99,15 @@ fn walk_unsafe(
97 } 99 }
98 } 100 }
99 } 101 }
102 Expr::Path(path) => {
103 let resolver = resolver_for_expr(db.upcast(), def, current);
104 let value_or_partial = resolver.resolve_path_in_value_ns(db.upcast(), path.mod_path());
105 if let Some(ResolveValueResult::ValueNs(ValueNs::StaticId(id))) = value_or_partial {
106 if db.static_data(id).mutable {
107 unsafe_exprs.push(UnsafeExpr { expr: current, inside_unsafe_block });
108 }
109 }
110 }
100 Expr::MethodCall { .. } => { 111 Expr::MethodCall { .. } => {
101 if infer 112 if infer
102 .method_resolution(current) 113 .method_resolution(current)
@@ -112,13 +123,13 @@ fn walk_unsafe(
112 } 123 }
113 } 124 }
114 Expr::Unsafe { body: child } => { 125 Expr::Unsafe { body: child } => {
115 return walk_unsafe(unsafe_exprs, db, infer, body, *child, true); 126 return walk_unsafe(unsafe_exprs, db, infer, def, body, *child, true);
116 } 127 }
117 _ => {} 128 _ => {}
118 } 129 }
119 130
120 expr.walk_child_exprs(|child| { 131 expr.walk_child_exprs(|child| {
121 walk_unsafe(unsafe_exprs, db, infer, body, child, inside_unsafe_block); 132 walk_unsafe(unsafe_exprs, db, infer, def, body, child, inside_unsafe_block);
122 }); 133 });
123} 134}
124 135
@@ -170,4 +181,25 @@ fn main() {
170"#, 181"#,
171 ); 182 );
172 } 183 }
184
185 #[test]
186 fn missing_unsafe_diagnostic_with_static_mut() {
187 check_diagnostics(
188 r#"
189struct Ty {
190 a: u8,
191}
192
193static mut static_mut: Ty = Ty { a: 0 };
194
195fn main() {
196 let x = static_mut.a;
197 //^^^^^^^^^^ This operation is unsafe and requires an unsafe function or block
198 unsafe {
199 let x = static_mut.a;
200 }
201}
202"#,
203 );
204 }
173} 205}
diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs
index 28f32a0a4..3d12039a6 100644
--- a/crates/ra_hir_ty/src/infer.rs
+++ b/crates/ra_hir_ty/src/infer.rs
@@ -440,6 +440,12 @@ impl<'a> InferenceContext<'a> {
440 let ty = self.insert_type_vars(ty.subst(&substs)); 440 let ty = self.insert_type_vars(ty.subst(&substs));
441 forbid_unresolved_segments((ty, Some(strukt.into())), unresolved) 441 forbid_unresolved_segments((ty, Some(strukt.into())), unresolved)
442 } 442 }
443 TypeNs::AdtId(AdtId::UnionId(u)) => {
444 let substs = Ty::substs_from_path(&ctx, path, u.into(), true);
445 let ty = self.db.ty(u.into());
446 let ty = self.insert_type_vars(ty.subst(&substs));
447 forbid_unresolved_segments((ty, Some(u.into())), unresolved)
448 }
443 TypeNs::EnumVariantId(var) => { 449 TypeNs::EnumVariantId(var) => {
444 let substs = Ty::substs_from_path(&ctx, path, var.into(), true); 450 let substs = Ty::substs_from_path(&ctx, path, var.into(), true);
445 let ty = self.db.ty(var.parent.into()); 451 let ty = self.db.ty(var.parent.into());
@@ -490,10 +496,7 @@ impl<'a> InferenceContext<'a> {
490 // FIXME potentially resolve assoc type 496 // FIXME potentially resolve assoc type
491 (Ty::Unknown, None) 497 (Ty::Unknown, None)
492 } 498 }
493 TypeNs::AdtId(AdtId::EnumId(_)) 499 TypeNs::AdtId(AdtId::EnumId(_)) | TypeNs::BuiltinType(_) | TypeNs::TraitId(_) => {
494 | TypeNs::AdtId(AdtId::UnionId(_))
495 | TypeNs::BuiltinType(_)
496 | TypeNs::TraitId(_) => {
497 // FIXME diagnostic 500 // FIXME diagnostic
498 (Ty::Unknown, None) 501 (Ty::Unknown, None)
499 } 502 }
diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs
index 1eacc6f95..7638f167b 100644
--- a/crates/ra_hir_ty/src/lower.rs
+++ b/crates/ra_hir_ty/src/lower.rs
@@ -518,6 +518,7 @@ impl Ty {
518 let (segment, generic_def) = match resolved { 518 let (segment, generic_def) = match resolved {
519 ValueTyDefId::FunctionId(it) => (last, Some(it.into())), 519 ValueTyDefId::FunctionId(it) => (last, Some(it.into())),
520 ValueTyDefId::StructId(it) => (last, Some(it.into())), 520 ValueTyDefId::StructId(it) => (last, Some(it.into())),
521 ValueTyDefId::UnionId(it) => (last, Some(it.into())),
521 ValueTyDefId::ConstId(it) => (last, Some(it.into())), 522 ValueTyDefId::ConstId(it) => (last, Some(it.into())),
522 ValueTyDefId::StaticId(_) => (last, None), 523 ValueTyDefId::StaticId(_) => (last, None),
523 ValueTyDefId::EnumVariantId(var) => { 524 ValueTyDefId::EnumVariantId(var) => {
@@ -1148,11 +1149,12 @@ impl_from!(BuiltinType, AdtId(StructId, EnumId, UnionId), TypeAliasId for TyDefI
1148pub enum ValueTyDefId { 1149pub enum ValueTyDefId {
1149 FunctionId(FunctionId), 1150 FunctionId(FunctionId),
1150 StructId(StructId), 1151 StructId(StructId),
1152 UnionId(UnionId),
1151 EnumVariantId(EnumVariantId), 1153 EnumVariantId(EnumVariantId),
1152 ConstId(ConstId), 1154 ConstId(ConstId),
1153 StaticId(StaticId), 1155 StaticId(StaticId),
1154} 1156}
1155impl_from!(FunctionId, StructId, EnumVariantId, ConstId, StaticId for ValueTyDefId); 1157impl_from!(FunctionId, StructId, UnionId, EnumVariantId, ConstId, StaticId for ValueTyDefId);
1156 1158
1157/// Build the declared type of an item. This depends on the namespace; e.g. for 1159/// Build the declared type of an item. This depends on the namespace; e.g. for
1158/// `struct Foo(usize)`, we have two types: The type of the struct itself, and 1160/// `struct Foo(usize)`, we have two types: The type of the struct itself, and
@@ -1179,6 +1181,7 @@ pub(crate) fn value_ty_query(db: &dyn HirDatabase, def: ValueTyDefId) -> Binders
1179 match def { 1181 match def {
1180 ValueTyDefId::FunctionId(it) => type_for_fn(db, it), 1182 ValueTyDefId::FunctionId(it) => type_for_fn(db, it),
1181 ValueTyDefId::StructId(it) => type_for_struct_constructor(db, it), 1183 ValueTyDefId::StructId(it) => type_for_struct_constructor(db, it),
1184 ValueTyDefId::UnionId(it) => type_for_adt(db, it.into()),
1182 ValueTyDefId::EnumVariantId(it) => type_for_enum_variant_constructor(db, it), 1185 ValueTyDefId::EnumVariantId(it) => type_for_enum_variant_constructor(db, it),
1183 ValueTyDefId::ConstId(it) => type_for_const(db, it), 1186 ValueTyDefId::ConstId(it) => type_for_const(db, it),
1184 ValueTyDefId::StaticId(it) => type_for_static(db, it), 1187 ValueTyDefId::StaticId(it) => type_for_static(db, it),
diff --git a/crates/ra_hir_ty/src/tests/simple.rs b/crates/ra_hir_ty/src/tests/simple.rs
index 3fd7d5cd4..5a7cf9455 100644
--- a/crates/ra_hir_ty/src/tests/simple.rs
+++ b/crates/ra_hir_ty/src/tests/simple.rs
@@ -334,16 +334,44 @@ fn infer_union() {
334 bar: f32, 334 bar: f32,
335 } 335 }
336 336
337 fn test() {
338 let u = MyUnion { foo: 0 };
339 unsafe { baz(u); }
340 let u = MyUnion { bar: 0.0 };
341 unsafe { baz(u); }
342 }
343
337 unsafe fn baz(u: MyUnion) { 344 unsafe fn baz(u: MyUnion) {
338 let inner = u.foo; 345 let inner = u.foo;
346 let inner = u.bar;
339 } 347 }
340 "#, 348 "#,
341 expect![[r#" 349 expect![[r#"
342 61..62 'u': MyUnion 350 57..172 '{ ...); } }': ()
343 73..99 '{ ...foo; }': () 351 67..68 'u': MyUnion
344 83..88 'inner': u32 352 71..89 'MyUnio...o: 0 }': MyUnion
345 91..92 'u': MyUnion 353 86..87 '0': u32
346 91..96 'u.foo': u32 354 95..113 'unsafe...(u); }': ()
355 102..113 '{ baz(u); }': ()
356 104..107 'baz': fn baz(MyUnion)
357 104..110 'baz(u)': ()
358 108..109 'u': MyUnion
359 122..123 'u': MyUnion
360 126..146 'MyUnio... 0.0 }': MyUnion
361 141..144 '0.0': f32
362 152..170 'unsafe...(u); }': ()
363 159..170 '{ baz(u); }': ()
364 161..164 'baz': fn baz(MyUnion)
365 161..167 'baz(u)': ()
366 165..166 'u': MyUnion
367 188..189 'u': MyUnion
368 200..249 '{ ...bar; }': ()
369 210..215 'inner': u32
370 218..219 'u': MyUnion
371 218..223 'u.foo': u32
372 233..238 'inner': f32
373 241..242 'u': MyUnion
374 241..246 'u.bar': f32
347 "#]], 375 "#]],
348 ); 376 );
349} 377}