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 56acd3bbf..45e31033e 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;
@@ -41,7 +41,7 @@ impl Diagnostic for NoSuchField {
41 "no such field".to_string() 41 "no such field".to_string()
42 } 42 }
43 43
44 fn source(&self) -> InFile<SyntaxNodePtr> { 44 fn display_source(&self) -> InFile<SyntaxNodePtr> {
45 InFile::new(self.file, self.field.clone().into()) 45 InFile::new(self.file, self.field.clone().into())
46 } 46 }
47 47
@@ -50,20 +50,11 @@ impl Diagnostic for NoSuchField {
50 } 50 }
51} 51}
52 52
53impl AstDiagnostic for NoSuchField {
54 type AST = ast::RecordExprField;
55
56 fn ast(&self, db: &dyn AstDatabase) -> Self::AST {
57 let root = db.parse_or_expand(self.source().file_id).unwrap();
58 let node = self.source().value.to_node(&root);
59 ast::RecordExprField::cast(node).unwrap()
60 }
61}
62
63#[derive(Debug)] 53#[derive(Debug)]
64pub struct MissingFields { 54pub struct MissingFields {
65 pub file: HirFileId, 55 pub file: HirFileId,
66 pub field_list: AstPtr<ast::RecordExprFieldList>, 56 pub field_list_parent: AstPtr<ast::RecordExpr>,
57 pub field_list_parent_path: Option<AstPtr<ast::Path>>,
67 pub missed_fields: Vec<Name>, 58 pub missed_fields: Vec<Name>,
68} 59}
69 60
@@ -78,28 +69,28 @@ impl Diagnostic for MissingFields {
78 } 69 }
79 buf 70 buf
80 } 71 }
81 fn source(&self) -> InFile<SyntaxNodePtr> { 72
82 InFile { file_id: self.file, value: self.field_list.clone().into() } 73 fn display_source(&self) -> InFile<SyntaxNodePtr> {
74 InFile {
75 file_id: self.file,
76 value: self
77 .field_list_parent_path
78 .clone()
79 .map(SyntaxNodePtr::from)
80 .unwrap_or_else(|| self.field_list_parent.clone().into()),
81 }
83 } 82 }
83
84 fn as_any(&self) -> &(dyn Any + Send + 'static) { 84 fn as_any(&self) -> &(dyn Any + Send + 'static) {
85 self 85 self
86 } 86 }
87} 87}
88 88
89impl AstDiagnostic for MissingFields {
90 type AST = ast::RecordExprFieldList;
91
92 fn ast(&self, db: &dyn AstDatabase) -> Self::AST {
93 let root = db.parse_or_expand(self.source().file_id).unwrap();
94 let node = self.source().value.to_node(&root);
95 ast::RecordExprFieldList::cast(node).unwrap()
96 }
97}
98
99#[derive(Debug)] 89#[derive(Debug)]
100pub struct MissingPatFields { 90pub struct MissingPatFields {
101 pub file: HirFileId, 91 pub file: HirFileId,
102 pub field_list: AstPtr<ast::RecordPatFieldList>, 92 pub field_list_parent: AstPtr<ast::RecordPat>,
93 pub field_list_parent_path: Option<AstPtr<ast::Path>>,
103 pub missed_fields: Vec<Name>, 94 pub missed_fields: Vec<Name>,
104} 95}
105 96
@@ -114,8 +105,15 @@ impl Diagnostic for MissingPatFields {
114 } 105 }
115 buf 106 buf
116 } 107 }
117 fn source(&self) -> InFile<SyntaxNodePtr> { 108 fn display_source(&self) -> InFile<SyntaxNodePtr> {
118 InFile { file_id: self.file, value: self.field_list.clone().into() } 109 InFile {
110 file_id: self.file,
111 value: self
112 .field_list_parent_path
113 .clone()
114 .map(SyntaxNodePtr::from)
115 .unwrap_or_else(|| self.field_list_parent.clone().into()),
116 }
119 } 117 }
120 fn as_any(&self) -> &(dyn Any + Send + 'static) { 118 fn as_any(&self) -> &(dyn Any + Send + 'static) {
121 self 119 self
@@ -136,7 +134,7 @@ impl Diagnostic for MissingMatchArms {
136 fn message(&self) -> String { 134 fn message(&self) -> String {
137 String::from("Missing match arm") 135 String::from("Missing match arm")
138 } 136 }
139 fn source(&self) -> InFile<SyntaxNodePtr> { 137 fn display_source(&self) -> InFile<SyntaxNodePtr> {
140 InFile { file_id: self.file, value: self.match_expr.clone().into() } 138 InFile { file_id: self.file, value: self.match_expr.clone().into() }
141 } 139 }
142 fn as_any(&self) -> &(dyn Any + Send + 'static) { 140 fn as_any(&self) -> &(dyn Any + Send + 'static) {
@@ -157,7 +155,7 @@ impl Diagnostic for MissingOkInTailExpr {
157 fn message(&self) -> String { 155 fn message(&self) -> String {
158 "wrap return expression in Ok".to_string() 156 "wrap return expression in Ok".to_string()
159 } 157 }
160 fn source(&self) -> InFile<SyntaxNodePtr> { 158 fn display_source(&self) -> InFile<SyntaxNodePtr> {
161 InFile { file_id: self.file, value: self.expr.clone().into() } 159 InFile { file_id: self.file, value: self.expr.clone().into() }
162 } 160 }
163 fn as_any(&self) -> &(dyn Any + Send + 'static) { 161 fn as_any(&self) -> &(dyn Any + Send + 'static) {
@@ -165,16 +163,6 @@ impl Diagnostic for MissingOkInTailExpr {
165 } 163 }
166} 164}
167 165
168impl AstDiagnostic for MissingOkInTailExpr {
169 type AST = ast::Expr;
170
171 fn ast(&self, db: &dyn AstDatabase) -> Self::AST {
172 let root = db.parse_or_expand(self.file).unwrap();
173 let node = self.source().value.to_node(&root);
174 ast::Expr::cast(node).unwrap()
175 }
176}
177
178#[derive(Debug)] 166#[derive(Debug)]
179pub struct BreakOutsideOfLoop { 167pub struct BreakOutsideOfLoop {
180 pub file: HirFileId, 168 pub file: HirFileId,
@@ -188,7 +176,7 @@ impl Diagnostic for BreakOutsideOfLoop {
188 fn message(&self) -> String { 176 fn message(&self) -> String {
189 "break outside of loop".to_string() 177 "break outside of loop".to_string()
190 } 178 }
191 fn source(&self) -> InFile<SyntaxNodePtr> { 179 fn display_source(&self) -> InFile<SyntaxNodePtr> {
192 InFile { file_id: self.file, value: self.expr.clone().into() } 180 InFile { file_id: self.file, value: self.expr.clone().into() }
193 } 181 }
194 fn as_any(&self) -> &(dyn Any + Send + 'static) { 182 fn as_any(&self) -> &(dyn Any + Send + 'static) {
@@ -196,16 +184,6 @@ impl Diagnostic for BreakOutsideOfLoop {
196 } 184 }
197} 185}
198 186
199impl AstDiagnostic for BreakOutsideOfLoop {
200 type AST = ast::Expr;
201
202 fn ast(&self, db: &dyn AstDatabase) -> Self::AST {
203 let root = db.parse_or_expand(self.file).unwrap();
204 let node = self.source().value.to_node(&root);
205 ast::Expr::cast(node).unwrap()
206 }
207}
208
209#[derive(Debug)] 187#[derive(Debug)]
210pub struct MissingUnsafe { 188pub struct MissingUnsafe {
211 pub file: HirFileId, 189 pub file: HirFileId,
@@ -219,7 +197,7 @@ impl Diagnostic for MissingUnsafe {
219 fn message(&self) -> String { 197 fn message(&self) -> String {
220 format!("This operation is unsafe and requires an unsafe function or block") 198 format!("This operation is unsafe and requires an unsafe function or block")
221 } 199 }
222 fn source(&self) -> InFile<SyntaxNodePtr> { 200 fn display_source(&self) -> InFile<SyntaxNodePtr> {
223 InFile { file_id: self.file, value: self.expr.clone().into() } 201 InFile { file_id: self.file, value: self.expr.clone().into() }
224 } 202 }
225 fn as_any(&self) -> &(dyn Any + Send + 'static) { 203 fn as_any(&self) -> &(dyn Any + Send + 'static) {
@@ -227,16 +205,6 @@ impl Diagnostic for MissingUnsafe {
227 } 205 }
228} 206}
229 207
230impl AstDiagnostic for MissingUnsafe {
231 type AST = ast::Expr;
232
233 fn ast(&self, db: &dyn AstDatabase) -> Self::AST {
234 let root = db.parse_or_expand(self.source().file_id).unwrap();
235 let node = self.source().value.to_node(&root);
236 ast::Expr::cast(node).unwrap()
237 }
238}
239
240#[derive(Debug)] 208#[derive(Debug)]
241pub struct MismatchedArgCount { 209pub struct MismatchedArgCount {
242 pub file: HirFileId, 210 pub file: HirFileId,
@@ -253,7 +221,7 @@ impl Diagnostic for MismatchedArgCount {
253 let s = if self.expected == 1 { "" } else { "s" }; 221 let s = if self.expected == 1 { "" } else { "s" };
254 format!("Expected {} argument{}, found {}", self.expected, s, self.found) 222 format!("Expected {} argument{}, found {}", self.expected, s, self.found)
255 } 223 }
256 fn source(&self) -> InFile<SyntaxNodePtr> { 224 fn display_source(&self) -> InFile<SyntaxNodePtr> {
257 InFile { file_id: self.file, value: self.call_expr.clone().into() } 225 InFile { file_id: self.file, value: self.call_expr.clone().into() }
258 } 226 }
259 fn as_any(&self) -> &(dyn Any + Send + 'static) { 227 fn as_any(&self) -> &(dyn Any + Send + 'static) {
@@ -264,19 +232,13 @@ impl Diagnostic for MismatchedArgCount {
264 } 232 }
265} 233}
266 234
267impl AstDiagnostic for MismatchedArgCount {
268 type AST = ast::CallExpr;
269 fn ast(&self, db: &dyn AstDatabase) -> Self::AST {
270 let root = db.parse_or_expand(self.source().file_id).unwrap();
271 let node = self.source().value.to_node(&root);
272 ast::CallExpr::cast(node).unwrap()
273 }
274}
275
276#[cfg(test)] 235#[cfg(test)]
277mod tests { 236mod tests {
278 use hir_def::{db::DefDatabase, AssocItemId, ModuleDefId}; 237 use hir_def::{db::DefDatabase, AssocItemId, ModuleDefId};
279 use hir_expand::diagnostics::{Diagnostic, DiagnosticSinkBuilder}; 238 use hir_expand::{
239 db::AstDatabase,
240 diagnostics::{Diagnostic, DiagnosticSinkBuilder},
241 };
280 use ra_db::{fixture::WithFixture, FileId, SourceDatabase, SourceDatabaseExt}; 242 use ra_db::{fixture::WithFixture, FileId, SourceDatabase, SourceDatabaseExt};
281 use ra_syntax::{TextRange, TextSize}; 243 use ra_syntax::{TextRange, TextSize};
282 use rustc_hash::FxHashMap; 244 use rustc_hash::FxHashMap;
@@ -321,9 +283,11 @@ mod tests {
321 283
322 let mut actual: FxHashMap<FileId, Vec<(TextRange, String)>> = FxHashMap::default(); 284 let mut actual: FxHashMap<FileId, Vec<(TextRange, String)>> = FxHashMap::default();
323 db.diagnostics(|d| { 285 db.diagnostics(|d| {
324 // FXIME: macros... 286 let src = d.display_source();
325 let file_id = d.source().file_id.original_file(&db); 287 let root = db.parse_or_expand(src.file_id).unwrap();
326 let range = d.syntax_node(&db).text_range(); 288 // FIXME: macros...
289 let file_id = src.file_id.original_file(&db);
290 let range = src.value.to_node(&root).text_range();
327 let message = d.message().to_owned(); 291 let message = d.message().to_owned();
328 actual.entry(file_id).or_default().push((range, message)); 292 actual.entry(file_id).or_default().push((range, message));
329 }); 293 });
@@ -351,8 +315,8 @@ struct S { foo: i32, bar: () }
351impl S { 315impl S {
352 fn new() -> S { 316 fn new() -> S {
353 S { 317 S {
354 //^... Missing structure fields: 318 //^ Missing structure fields:
355 //| - bar 319 //| - bar
356 foo: 92, 320 foo: 92,
357 baz: 62, 321 baz: 62,
358 //^^^^^^^ no such field 322 //^^^^^^^ no such field
@@ -473,8 +437,8 @@ impl Foo {
473struct S { foo: i32, bar: () } 437struct S { foo: i32, bar: () }
474fn baz(s: S) { 438fn baz(s: S) {
475 let S { foo: _ } = s; 439 let S { foo: _ } = s;
476 //^^^^^^^^^^ Missing structure fields: 440 //^ Missing structure fields:
477 // | - bar 441 //| - bar
478} 442}
479"#, 443"#,
480 ); 444 );
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}