aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir')
-rw-r--r--crates/ra_hir/Cargo.toml1
-rw-r--r--crates/ra_hir/src/adt.rs70
-rw-r--r--crates/ra_hir/src/code_model_api.rs32
-rw-r--r--crates/ra_hir/src/db.rs10
-rw-r--r--crates/ra_hir/src/ids.rs9
-rw-r--r--crates/ra_hir/src/lib.rs2
-rw-r--r--crates/ra_hir/src/mock.rs8
-rw-r--r--crates/ra_hir/src/module_tree.rs25
-rw-r--r--crates/ra_hir/src/nameres.rs5
-rw-r--r--crates/ra_hir/src/nameres/lower.rs2
-rw-r--r--crates/ra_hir/src/nameres/tests.rs2
-rw-r--r--crates/ra_hir/src/query_definitions.rs7
-rw-r--r--crates/ra_hir/src/source_binder.rs4
-rw-r--r--crates/ra_hir/src/ty.rs60
-rw-r--r--crates/ra_hir/src/ty/snapshots/tests__bug_651.snap13
-rw-r--r--crates/ra_hir/src/ty/tests.rs17
16 files changed, 178 insertions, 89 deletions
diff --git a/crates/ra_hir/Cargo.toml b/crates/ra_hir/Cargo.toml
index 3d802ade4..57a4b155b 100644
--- a/crates/ra_hir/Cargo.toml
+++ b/crates/ra_hir/Cargo.toml
@@ -12,7 +12,6 @@ rustc-hash = "1.0"
12parking_lot = "0.7.0" 12parking_lot = "0.7.0"
13ena = "0.11" 13ena = "0.11"
14join_to_string = "0.1.3" 14join_to_string = "0.1.3"
15salsa = "0.10.0-alpha3"
16 15
17ra_syntax = { path = "../ra_syntax" } 16ra_syntax = { path = "../ra_syntax" }
18ra_arena = { path = "../ra_arena" } 17ra_arena = { path = "../ra_arena" }
diff --git a/crates/ra_hir/src/adt.rs b/crates/ra_hir/src/adt.rs
index ec6a10353..22bbad964 100644
--- a/crates/ra_hir/src/adt.rs
+++ b/crates/ra_hir/src/adt.rs
@@ -11,7 +11,7 @@ use ra_syntax::{
11 11
12use crate::{ 12use crate::{
13 Name, AsName, Struct, Enum, EnumVariant, Crate, 13 Name, AsName, Struct, Enum, EnumVariant, Crate,
14 HirDatabase, HirFileId, 14 HirDatabase, HirFileId, StructField, FieldSource,
15 type_ref::TypeRef, 15 type_ref::TypeRef,
16}; 16};
17 17
@@ -150,7 +150,7 @@ impl VariantData {
150impl VariantData { 150impl VariantData {
151 fn new(flavor: StructFlavor) -> Self { 151 fn new(flavor: StructFlavor) -> Self {
152 let inner = match flavor { 152 let inner = match flavor {
153 StructFlavor::Tuple(fl) => { 153 ast::StructFlavor::Tuple(fl) => {
154 let fields = fl 154 let fields = fl
155 .fields() 155 .fields()
156 .enumerate() 156 .enumerate()
@@ -161,7 +161,7 @@ impl VariantData {
161 .collect(); 161 .collect();
162 VariantDataInner::Tuple(fields) 162 VariantDataInner::Tuple(fields)
163 } 163 }
164 StructFlavor::Named(fl) => { 164 ast::StructFlavor::Named(fl) => {
165 let fields = fl 165 let fields = fl
166 .fields() 166 .fields()
167 .map(|fd| StructFieldData { 167 .map(|fd| StructFieldData {
@@ -171,8 +171,70 @@ impl VariantData {
171 .collect(); 171 .collect();
172 VariantDataInner::Struct(fields) 172 VariantDataInner::Struct(fields)
173 } 173 }
174 StructFlavor::Unit => VariantDataInner::Unit, 174 ast::StructFlavor::Unit => VariantDataInner::Unit,
175 }; 175 };
176 VariantData(inner) 176 VariantData(inner)
177 } 177 }
178} 178}
179
180#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
181pub enum VariantDef {
182 Struct(Struct),
183 EnumVariant(EnumVariant),
184}
185impl_froms!(VariantDef: Struct, EnumVariant);
186
187impl VariantDef {
188 pub(crate) fn field(self, db: &impl HirDatabase, name: &Name) -> Option<StructField> {
189 match self {
190 VariantDef::Struct(it) => it.field(db, name),
191 VariantDef::EnumVariant(it) => it.field(db, name),
192 }
193 }
194 pub(crate) fn variant_data(self, db: &impl HirDatabase) -> Arc<VariantData> {
195 match self {
196 VariantDef::Struct(it) => it.variant_data(db),
197 VariantDef::EnumVariant(it) => it.variant_data(db),
198 }
199 }
200}
201
202impl StructField {
203 pub(crate) fn source_impl(&self, db: &impl HirDatabase) -> (HirFileId, FieldSource) {
204 let var_data = self.parent.variant_data(db);
205 let fields = var_data.fields().unwrap();
206 let ss;
207 let es;
208 let (file_id, struct_flavor) = match self.parent {
209 VariantDef::Struct(s) => {
210 let (file_id, source) = s.source(db);
211 ss = source;
212 (file_id, ss.flavor())
213 }
214 VariantDef::EnumVariant(e) => {
215 let (file_id, source) = e.source(db);
216 es = source;
217 (file_id, es.flavor())
218 }
219 };
220
221 let field_sources = match struct_flavor {
222 ast::StructFlavor::Tuple(fl) => fl
223 .fields()
224 .map(|it| FieldSource::Pos(it.to_owned()))
225 .collect(),
226 ast::StructFlavor::Named(fl) => fl
227 .fields()
228 .map(|it| FieldSource::Named(it.to_owned()))
229 .collect(),
230 ast::StructFlavor::Unit => Vec::new(),
231 };
232 let field = field_sources
233 .into_iter()
234 .zip(fields.iter())
235 .find(|(_syntax, (id, _))| *id == self.id)
236 .unwrap()
237 .0;
238 (file_id, field)
239 }
240}
diff --git a/crates/ra_hir/src/code_model_api.rs b/crates/ra_hir/src/code_model_api.rs
index 118562984..191104890 100644
--- a/crates/ra_hir/src/code_model_api.rs
+++ b/crates/ra_hir/src/code_model_api.rs
@@ -10,8 +10,8 @@ use crate::{
10 nameres::{ModuleScope, lower::ImportId}, 10 nameres::{ModuleScope, lower::ImportId},
11 db::HirDatabase, 11 db::HirDatabase,
12 expr::BodySyntaxMapping, 12 expr::BodySyntaxMapping,
13 ty::{InferenceResult, VariantDef}, 13 ty::InferenceResult,
14 adt::{EnumVariantId, StructFieldId}, 14 adt::{EnumVariantId, StructFieldId, VariantDef},
15 generics::GenericParams, 15 generics::GenericParams,
16 docs::{Documentation, Docs, docs_from_ast}, 16 docs::{Documentation, Docs, docs_from_ast},
17 module_tree::ModuleId, 17 module_tree::ModuleId,
@@ -177,12 +177,25 @@ impl Module {
177 } 177 }
178} 178}
179 179
180impl Docs for Module {
181 fn docs(&self, db: &impl HirDatabase) -> Option<Documentation> {
182 self.declaration_source(db)
183 .and_then(|it| docs_from_ast(&*it.1))
184 }
185}
186
180#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 187#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
181pub struct StructField { 188pub struct StructField {
182 parent: VariantDef, 189 pub(crate) parent: VariantDef,
183 pub(crate) id: StructFieldId, 190 pub(crate) id: StructFieldId,
184} 191}
185 192
193#[derive(Debug)]
194pub enum FieldSource {
195 Named(TreeArc<ast::NamedFieldDef>),
196 Pos(TreeArc<ast::PosFieldDef>),
197}
198
186impl StructField { 199impl StructField {
187 pub fn name(&self, db: &impl HirDatabase) -> Name { 200 pub fn name(&self, db: &impl HirDatabase) -> Name {
188 self.parent.variant_data(db).fields().unwrap()[self.id] 201 self.parent.variant_data(db).fields().unwrap()[self.id]
@@ -190,6 +203,10 @@ impl StructField {
190 .clone() 203 .clone()
191 } 204 }
192 205
206 pub fn source(&self, db: &impl HirDatabase) -> (HirFileId, FieldSource) {
207 self.source_impl(db)
208 }
209
193 pub fn ty(&self, db: &impl HirDatabase) -> Ty { 210 pub fn ty(&self, db: &impl HirDatabase) -> Ty {
194 db.type_for_field(*self) 211 db.type_for_field(*self)
195 } 212 }
@@ -199,6 +216,15 @@ impl StructField {
199 } 216 }
200} 217}
201 218
219impl Docs for StructField {
220 fn docs(&self, db: &impl HirDatabase) -> Option<Documentation> {
221 match self.source(db).1 {
222 FieldSource::Named(named) => docs_from_ast(&*named),
223 FieldSource::Pos(..) => return None,
224 }
225 }
226}
227
202#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 228#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
203pub struct Struct { 229pub struct Struct {
204 pub(crate) id: StructId, 230 pub(crate) id: StructId,
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs
index 3c82262a2..5df4bd4a1 100644
--- a/crates/ra_hir/src/db.rs
+++ b/crates/ra_hir/src/db.rs
@@ -1,7 +1,7 @@
1use std::sync::Arc; 1use std::sync::Arc;
2 2
3use ra_syntax::{SyntaxNode, TreeArc, SourceFile}; 3use ra_syntax::{SyntaxNode, TreeArc, SourceFile};
4use ra_db::{SyntaxDatabase, CrateId, salsa}; 4use ra_db::{SourceDatabase, CrateId, salsa};
5 5
6use crate::{ 6use crate::{
7 MacroCallId, HirFileId, 7 MacroCallId, HirFileId,
@@ -18,10 +18,10 @@ use crate::{
18 generics::{GenericParams, GenericDef}, 18 generics::{GenericParams, GenericDef},
19}; 19};
20 20
21#[salsa::query_group] 21#[salsa::query_group(HirDatabaseStorage)]
22pub trait HirDatabase: SyntaxDatabase + AsRef<HirInterner> { 22pub trait HirDatabase: SourceDatabase + AsRef<HirInterner> {
23 #[salsa::invoke(HirFileId::hir_source_file)] 23 #[salsa::invoke(HirFileId::hir_parse)]
24 fn hir_source_file(&self, file_id: HirFileId) -> TreeArc<SourceFile>; 24 fn hir_parse(&self, file_id: HirFileId) -> TreeArc<SourceFile>;
25 25
26 #[salsa::invoke(crate::macros::expand_macro_invocation)] 26 #[salsa::invoke(crate::macros::expand_macro_invocation)]
27 fn expand_macro_invocation(&self, invoc: MacroCallId) -> Option<Arc<MacroExpansion>>; 27 fn expand_macro_invocation(&self, invoc: MacroCallId) -> Option<Arc<MacroExpansion>>;
diff --git a/crates/ra_hir/src/ids.rs b/crates/ra_hir/src/ids.rs
index 5272656ec..7dd4b540e 100644
--- a/crates/ra_hir/src/ids.rs
+++ b/crates/ra_hir/src/ids.rs
@@ -86,12 +86,9 @@ impl HirFileId {
86 } 86 }
87 } 87 }
88 88
89 pub(crate) fn hir_source_file( 89 pub(crate) fn hir_parse(db: &impl HirDatabase, file_id: HirFileId) -> TreeArc<SourceFile> {
90 db: &impl HirDatabase,
91 file_id: HirFileId,
92 ) -> TreeArc<SourceFile> {
93 match file_id.0 { 90 match file_id.0 {
94 HirFileIdRepr::File(file_id) => db.source_file(file_id), 91 HirFileIdRepr::File(file_id) => db.parse(file_id),
95 HirFileIdRepr::Macro(m) => { 92 HirFileIdRepr::Macro(m) => {
96 if let Some(exp) = db.expand_macro_invocation(m) { 93 if let Some(exp) = db.expand_macro_invocation(m) {
97 return exp.file(); 94 return exp.file();
@@ -370,7 +367,7 @@ impl SourceFileItems {
370 self.arena.iter().map(|(_id, i)| i).collect::<Vec<_>>(), 367 self.arena.iter().map(|(_id, i)| i).collect::<Vec<_>>(),
371 ); 368 );
372 } 369 }
373 pub fn id_of_source_file(&self) -> SourceFileItemId { 370 pub fn id_of_parse(&self) -> SourceFileItemId {
374 let (id, _syntax) = self.arena.iter().next().unwrap(); 371 let (id, _syntax) = self.arena.iter().next().unwrap();
375 id 372 id
376 } 373 }
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs
index 596f9c38c..eaf8565ee 100644
--- a/crates/ra_hir/src/lib.rs
+++ b/crates/ra_hir/src/lib.rs
@@ -68,7 +68,7 @@ pub use self::code_model_api::{
68 Module, ModuleDef, ModuleSource, Problem, 68 Module, ModuleDef, ModuleSource, Problem,
69 Struct, Enum, EnumVariant, 69 Struct, Enum, EnumVariant,
70 Function, FnSignature, ScopeEntryWithSyntax, 70 Function, FnSignature, ScopeEntryWithSyntax,
71 StructField, 71 StructField, FieldSource,
72 Static, Const, 72 Static, Const,
73 Trait, Type, 73 Trait, Type,
74}; 74};
diff --git a/crates/ra_hir/src/mock.rs b/crates/ra_hir/src/mock.rs
index 36b174cd6..7da15eca0 100644
--- a/crates/ra_hir/src/mock.rs
+++ b/crates/ra_hir/src/mock.rs
@@ -2,7 +2,7 @@ use std::{sync::Arc, panic};
2 2
3use parking_lot::Mutex; 3use parking_lot::Mutex;
4use ra_db::{ 4use ra_db::{
5 BaseDatabase, FilePosition, FileId, CrateGraph, SourceRoot, SourceRootId, FilesDatabase, 5 CheckCanceled, FilePosition, FileId, CrateGraph, SourceRoot, SourceRootId, SourceDatabase, salsa,
6}; 6};
7use relative_path::RelativePathBuf; 7use relative_path::RelativePathBuf;
8use test_utils::{parse_fixture, CURSOR_MARKER, extract_offset}; 8use test_utils::{parse_fixture, CURSOR_MARKER, extract_offset};
@@ -11,7 +11,7 @@ use crate::{db, HirInterner};
11 11
12pub const WORKSPACE: SourceRootId = SourceRootId(0); 12pub const WORKSPACE: SourceRootId = SourceRootId(0);
13 13
14#[salsa::database(ra_db::FilesDatabase, ra_db::SyntaxDatabase, db::HirDatabase)] 14#[salsa::database(ra_db::SourceDatabaseStorage, db::HirDatabaseStorage)]
15#[derive(Debug)] 15#[derive(Debug)]
16pub(crate) struct MockDatabase { 16pub(crate) struct MockDatabase {
17 events: Mutex<Option<Vec<salsa::Event<MockDatabase>>>>, 17 events: Mutex<Option<Vec<salsa::Event<MockDatabase>>>>,
@@ -140,8 +140,6 @@ impl Default for MockDatabase {
140 file_counter: 0, 140 file_counter: 0,
141 }; 141 };
142 db.set_crate_graph(Default::default()); 142 db.set_crate_graph(Default::default());
143 db.set_local_roots(Default::default());
144 db.set_library_roots(Default::default());
145 db 143 db
146 } 144 }
147} 145}
@@ -157,7 +155,7 @@ impl salsa::ParallelDatabase for MockDatabase {
157 } 155 }
158} 156}
159 157
160impl BaseDatabase for MockDatabase {} 158impl CheckCanceled for MockDatabase {}
161 159
162impl AsRef<HirInterner> for MockDatabase { 160impl AsRef<HirInterner> for MockDatabase {
163 fn as_ref(&self) -> &HirInterner { 161 fn as_ref(&self) -> &HirInterner {
diff --git a/crates/ra_hir/src/module_tree.rs b/crates/ra_hir/src/module_tree.rs
index c00834c4c..d5ad9decb 100644
--- a/crates/ra_hir/src/module_tree.rs
+++ b/crates/ra_hir/src/module_tree.rs
@@ -1,6 +1,5 @@
1use std::sync::Arc; 1use std::sync::Arc;
2 2
3use rustc_hash::{FxHashMap, FxHashSet};
4use arrayvec::ArrayVec; 3use arrayvec::ArrayVec;
5use relative_path::RelativePathBuf; 4use relative_path::RelativePathBuf;
6use ra_db::{FileId, SourceRoot, CrateId}; 5use ra_db::{FileId, SourceRoot, CrateId};
@@ -147,28 +146,21 @@ impl ModuleTree {
147 let file_id = crate_graph.crate_root(crate_id); 146 let file_id = crate_graph.crate_root(crate_id);
148 let source_root_id = db.file_source_root(file_id); 147 let source_root_id = db.file_source_root(file_id);
149 148
150 let mut roots = FxHashMap::default();
151 let mut visited = FxHashSet::default();
152
153 let source_root = db.source_root(source_root_id); 149 let source_root = db.source_root(source_root_id);
154 let source = SourceItemId { 150 let source = SourceItemId {
155 file_id: file_id.into(), 151 file_id: file_id.into(),
156 item_id: None, 152 item_id: None,
157 }; 153 };
158 let module_id = self.init_subtree(db, &source_root, &mut visited, &mut roots, None, source); 154 self.init_subtree(db, &source_root, None, source);
159 roots.insert(file_id, module_id);
160 } 155 }
161 156
162 fn init_subtree( 157 fn init_subtree(
163 &mut self, 158 &mut self,
164 db: &impl HirDatabase, 159 db: &impl HirDatabase,
165 source_root: &SourceRoot, 160 source_root: &SourceRoot,
166 visited: &mut FxHashSet<SourceItemId>,
167 roots: &mut FxHashMap<FileId, ModuleId>,
168 parent: Option<LinkId>, 161 parent: Option<LinkId>,
169 source: SourceItemId, 162 source: SourceItemId,
170 ) -> ModuleId { 163 ) -> ModuleId {
171 visited.insert(source);
172 let id = self.alloc_mod(ModuleData { 164 let id = self.alloc_mod(ModuleData {
173 source, 165 source,
174 parent, 166 parent,
@@ -187,28 +179,21 @@ impl ModuleTree {
187 let (points_to, problem) = resolve_submodule(db, source.file_id, &sub.name); 179 let (points_to, problem) = resolve_submodule(db, source.file_id, &sub.name);
188 let points_to = points_to 180 let points_to = points_to
189 .into_iter() 181 .into_iter()
190 .map(|file_id| match roots.remove(&file_id) { 182 .map(|file_id| {
191 Some(module_id) => { 183 self.init_subtree(
192 self.mods[module_id].parent = Some(link);
193 module_id
194 }
195 None => self.init_subtree(
196 db, 184 db,
197 source_root, 185 source_root,
198 visited,
199 roots,
200 Some(link), 186 Some(link),
201 SourceItemId { 187 SourceItemId {
202 file_id: file_id.into(), 188 file_id: file_id.into(),
203 item_id: None, 189 item_id: None,
204 }, 190 },
205 ), 191 )
206 }) 192 })
207 .collect::<Vec<_>>(); 193 .collect::<Vec<_>>();
208 (points_to, problem) 194 (points_to, problem)
209 } else { 195 } else {
210 let points_to = 196 let points_to = self.init_subtree(db, source_root, Some(link), sub.source);
211 self.init_subtree(db, source_root, visited, roots, Some(link), sub.source);
212 (vec![points_to], None) 197 (vec![points_to], None)
213 }; 198 };
214 199
diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs
index 028c1882f..5193900e0 100644
--- a/crates/ra_hir/src/nameres.rs
+++ b/crates/ra_hir/src/nameres.rs
@@ -190,7 +190,12 @@ where
190 self.populate_module(module_id, Arc::clone(items)); 190 self.populate_module(module_id, Arc::clone(items));
191 } 191 }
192 192
193 let mut iter = 0;
193 loop { 194 loop {
195 iter += 1;
196 if iter > 1000 {
197 panic!("failed to reach fixedpoint after 1000 iters")
198 }
194 let processed_imports_count = self.processed_imports.len(); 199 let processed_imports_count = self.processed_imports.len();
195 for &module_id in self.input.keys() { 200 for &module_id in self.input.keys() {
196 self.db.check_canceled(); 201 self.db.check_canceled();
diff --git a/crates/ra_hir/src/nameres/lower.rs b/crates/ra_hir/src/nameres/lower.rs
index b4fe99ea7..1d77548f3 100644
--- a/crates/ra_hir/src/nameres/lower.rs
+++ b/crates/ra_hir/src/nameres/lower.rs
@@ -129,7 +129,7 @@ impl LoweredModule {
129 let id = loc.id(db); 129 let id = loc.id(db);
130 let file_id = HirFileId::from(id); 130 let file_id = HirFileId::from(id);
131 //FIXME: expand recursively 131 //FIXME: expand recursively
132 for item in db.hir_source_file(file_id).items() { 132 for item in db.hir_parse(file_id).items() {
133 self.add_def_id(source_map, db, module, file_id, item); 133 self.add_def_id(source_map, db, module, file_id, item);
134 } 134 }
135 } 135 }
diff --git a/crates/ra_hir/src/nameres/tests.rs b/crates/ra_hir/src/nameres/tests.rs
index 24936976c..e72781f51 100644
--- a/crates/ra_hir/src/nameres/tests.rs
+++ b/crates/ra_hir/src/nameres/tests.rs
@@ -1,6 +1,6 @@
1use std::sync::Arc; 1use std::sync::Arc;
2 2
3use ra_db::{CrateGraph, SourceRootId, FilesDatabase}; 3use ra_db::{CrateGraph, SourceRootId, SourceDatabase};
4use relative_path::RelativePath; 4use relative_path::RelativePath;
5use test_utils::{assert_eq_text, covers}; 5use test_utils::{assert_eq_text, covers};
6 6
diff --git a/crates/ra_hir/src/query_definitions.rs b/crates/ra_hir/src/query_definitions.rs
index cf8c7e435..61c93a964 100644
--- a/crates/ra_hir/src/query_definitions.rs
+++ b/crates/ra_hir/src/query_definitions.rs
@@ -23,7 +23,7 @@ pub(super) fn fn_scopes(db: &impl HirDatabase, func: Function) -> Arc<FnScopes>
23} 23}
24 24
25pub(super) fn file_items(db: &impl HirDatabase, file_id: HirFileId) -> Arc<SourceFileItems> { 25pub(super) fn file_items(db: &impl HirDatabase, file_id: HirFileId) -> Arc<SourceFileItems> {
26 let source_file = db.hir_source_file(file_id); 26 let source_file = db.hir_parse(file_id);
27 let res = SourceFileItems::new(file_id, &source_file); 27 let res = SourceFileItems::new(file_id, &source_file);
28 Arc::new(res) 28 Arc::new(res)
29} 29}
@@ -34,10 +34,7 @@ pub(super) fn file_item(
34) -> TreeArc<SyntaxNode> { 34) -> TreeArc<SyntaxNode> {
35 match source_item_id.item_id { 35 match source_item_id.item_id {
36 Some(id) => db.file_items(source_item_id.file_id)[id].to_owned(), 36 Some(id) => db.file_items(source_item_id.file_id)[id].to_owned(),
37 None => db 37 None => db.hir_parse(source_item_id.file_id).syntax().to_owned(),
38 .hir_source_file(source_item_id.file_id)
39 .syntax()
40 .to_owned(),
41 } 38 }
42} 39}
43 40
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs
index dbe040805..c0b3f1cd4 100644
--- a/crates/ra_hir/src/source_binder.rs
+++ b/crates/ra_hir/src/source_binder.rs
@@ -43,7 +43,7 @@ pub fn module_from_declaration(
43 43
44/// Locates the module by position in the source code. 44/// Locates the module by position in the source code.
45pub fn module_from_position(db: &impl HirDatabase, position: FilePosition) -> Option<Module> { 45pub fn module_from_position(db: &impl HirDatabase, position: FilePosition) -> Option<Module> {
46 let file = db.source_file(position.file_id); 46 let file = db.parse(position.file_id);
47 match find_node_at_offset::<ast::Module>(file.syntax(), position.offset) { 47 match find_node_at_offset::<ast::Module>(file.syntax(), position.offset) {
48 Some(m) if !m.has_semi() => module_from_inline(db, position.file_id.into(), m), 48 Some(m) if !m.has_semi() => module_from_inline(db, position.file_id.into(), m),
49 _ => module_from_file_id(db, position.file_id.into()), 49 _ => module_from_file_id(db, position.file_id.into()),
@@ -95,7 +95,7 @@ fn module_from_source(db: &impl HirDatabase, source: SourceItemId) -> Option<Mod
95} 95}
96 96
97pub fn function_from_position(db: &impl HirDatabase, position: FilePosition) -> Option<Function> { 97pub fn function_from_position(db: &impl HirDatabase, position: FilePosition) -> Option<Function> {
98 let file = db.source_file(position.file_id); 98 let file = db.parse(position.file_id);
99 let fn_def = find_node_at_offset::<ast::FnDef>(file.syntax(), position.offset)?; 99 let fn_def = find_node_at_offset::<ast::FnDef>(file.syntax(), position.offset)?;
100 function_from_source(db, position.file_id, fn_def) 100 function_from_source(db, position.file_id, fn_def)
101} 101}
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs
index c57e222dd..179ebddee 100644
--- a/crates/ra_hir/src/ty.rs
+++ b/crates/ra_hir/src/ty.rs
@@ -38,7 +38,7 @@ use crate::{
38 expr::{Body, Expr, BindingAnnotation, Literal, ExprId, Pat, PatId, UnaryOp, BinaryOp, Statement, FieldPat}, 38 expr::{Body, Expr, BindingAnnotation, Literal, ExprId, Pat, PatId, UnaryOp, BinaryOp, Statement, FieldPat},
39 generics::GenericParams, 39 generics::GenericParams,
40 path::GenericArg, 40 path::GenericArg,
41 adt::VariantData, 41 adt::VariantDef,
42}; 42};
43 43
44/// The ID of a type variable. 44/// The ID of a type variable.
@@ -696,28 +696,6 @@ pub(super) fn type_for_def(db: &impl HirDatabase, def: TypableDef) -> Ty {
696 } 696 }
697} 697}
698 698
699#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
700pub enum VariantDef {
701 Struct(Struct),
702 EnumVariant(EnumVariant),
703}
704impl_froms!(VariantDef: Struct, EnumVariant);
705
706impl VariantDef {
707 pub(crate) fn field(self, db: &impl HirDatabase, name: &Name) -> Option<StructField> {
708 match self {
709 VariantDef::Struct(it) => it.field(db, name),
710 VariantDef::EnumVariant(it) => it.field(db, name),
711 }
712 }
713 pub(crate) fn variant_data(self, db: &impl HirDatabase) -> Arc<VariantData> {
714 match self {
715 VariantDef::Struct(it) => it.variant_data(db),
716 VariantDef::EnumVariant(it) => it.variant_data(db),
717 }
718 }
719}
720
721pub(super) fn type_for_field(db: &impl HirDatabase, field: StructField) -> Ty { 699pub(super) fn type_for_field(db: &impl HirDatabase, field: StructField) -> Ty {
722 let parent_def = field.parent_def(db); 700 let parent_def = field.parent_def(db);
723 let (generics, module) = match parent_def { 701 let (generics, module) = match parent_def {
@@ -732,8 +710,10 @@ pub(super) fn type_for_field(db: &impl HirDatabase, field: StructField) -> Ty {
732/// The result of type inference: A mapping from expressions and patterns to types. 710/// The result of type inference: A mapping from expressions and patterns to types.
733#[derive(Clone, PartialEq, Eq, Debug)] 711#[derive(Clone, PartialEq, Eq, Debug)]
734pub struct InferenceResult { 712pub struct InferenceResult {
735 /// For each method call expr, record the function it resolved to. 713 /// For each method call expr, records the function it resolves to.
736 method_resolutions: FxHashMap<ExprId, Function>, 714 method_resolutions: FxHashMap<ExprId, Function>,
715 /// For each field access expr, records the field it resolves to.
716 field_resolutions: FxHashMap<ExprId, StructField>,
737 type_of_expr: ArenaMap<ExprId, Ty>, 717 type_of_expr: ArenaMap<ExprId, Ty>,
738 type_of_pat: ArenaMap<PatId, Ty>, 718 type_of_pat: ArenaMap<PatId, Ty>,
739} 719}
@@ -742,6 +722,9 @@ impl InferenceResult {
742 pub fn method_resolution(&self, expr: ExprId) -> Option<Function> { 722 pub fn method_resolution(&self, expr: ExprId) -> Option<Function> {
743 self.method_resolutions.get(&expr).map(|it| *it) 723 self.method_resolutions.get(&expr).map(|it| *it)
744 } 724 }
725 pub fn field_resolution(&self, expr: ExprId) -> Option<StructField> {
726 self.field_resolutions.get(&expr).map(|it| *it)
727 }
745} 728}
746 729
747impl Index<ExprId> for InferenceResult { 730impl Index<ExprId> for InferenceResult {
@@ -770,6 +753,7 @@ struct InferenceContext<'a, D: HirDatabase> {
770 impl_block: Option<ImplBlock>, 753 impl_block: Option<ImplBlock>,
771 var_unification_table: InPlaceUnificationTable<TypeVarId>, 754 var_unification_table: InPlaceUnificationTable<TypeVarId>,
772 method_resolutions: FxHashMap<ExprId, Function>, 755 method_resolutions: FxHashMap<ExprId, Function>,
756 field_resolutions: FxHashMap<ExprId, StructField>,
773 type_of_expr: ArenaMap<ExprId, Ty>, 757 type_of_expr: ArenaMap<ExprId, Ty>,
774 type_of_pat: ArenaMap<PatId, Ty>, 758 type_of_pat: ArenaMap<PatId, Ty>,
775 /// The return type of the function being inferred. 759 /// The return type of the function being inferred.
@@ -806,7 +790,10 @@ fn binary_op_return_ty(op: BinaryOp, rhs_ty: Ty) -> Ty {
806 | BinaryOp::BitwiseAnd 790 | BinaryOp::BitwiseAnd
807 | BinaryOp::BitwiseOr 791 | BinaryOp::BitwiseOr
808 | BinaryOp::BitwiseXor => match rhs_ty { 792 | BinaryOp::BitwiseXor => match rhs_ty {
809 Ty::Int(..) | Ty::Float(..) => rhs_ty, 793 Ty::Int(..)
794 | Ty::Float(..)
795 | Ty::Infer(InferTy::IntVar(..))
796 | Ty::Infer(InferTy::FloatVar(..)) => rhs_ty,
810 _ => Ty::Unknown, 797 _ => Ty::Unknown,
811 }, 798 },
812 BinaryOp::RangeRightOpen | BinaryOp::RangeRightClosed => Ty::Unknown, 799 BinaryOp::RangeRightOpen | BinaryOp::RangeRightClosed => Ty::Unknown,
@@ -861,6 +848,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
861 ) -> Self { 848 ) -> Self {
862 InferenceContext { 849 InferenceContext {
863 method_resolutions: FxHashMap::default(), 850 method_resolutions: FxHashMap::default(),
851 field_resolutions: FxHashMap::default(),
864 type_of_expr: ArenaMap::default(), 852 type_of_expr: ArenaMap::default(),
865 type_of_pat: ArenaMap::default(), 853 type_of_pat: ArenaMap::default(),
866 var_unification_table: InPlaceUnificationTable::new(), 854 var_unification_table: InPlaceUnificationTable::new(),
@@ -886,6 +874,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
886 } 874 }
887 InferenceResult { 875 InferenceResult {
888 method_resolutions: mem::replace(&mut self.method_resolutions, Default::default()), 876 method_resolutions: mem::replace(&mut self.method_resolutions, Default::default()),
877 field_resolutions: mem::replace(&mut self.field_resolutions, Default::default()),
889 type_of_expr: expr_types, 878 type_of_expr: expr_types,
890 type_of_pat: pat_types, 879 type_of_pat: pat_types,
891 } 880 }
@@ -899,6 +888,10 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
899 self.method_resolutions.insert(expr, func); 888 self.method_resolutions.insert(expr, func);
900 } 889 }
901 890
891 fn write_field_resolution(&mut self, expr: ExprId, field: StructField) {
892 self.field_resolutions.insert(expr, field);
893 }
894
902 fn write_pat_ty(&mut self, pat: PatId, ty: Ty) { 895 fn write_pat_ty(&mut self, pat: PatId, ty: Ty) {
903 self.type_of_pat.insert(pat, ty); 896 self.type_of_pat.insert(pat, ty);
904 } 897 }
@@ -1251,9 +1244,9 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
1251 ty 1244 ty
1252 } 1245 }
1253 1246
1254 fn infer_expr(&mut self, expr: ExprId, expected: &Expectation) -> Ty { 1247 fn infer_expr(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty {
1255 let body = Arc::clone(&self.body); // avoid borrow checker problem 1248 let body = Arc::clone(&self.body); // avoid borrow checker problem
1256 let ty = match &body[expr] { 1249 let ty = match &body[tgt_expr] {
1257 Expr::Missing => Ty::Unknown, 1250 Expr::Missing => Ty::Unknown,
1258 Expr::If { 1251 Expr::If {
1259 condition, 1252 condition,
@@ -1344,7 +1337,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
1344 let resolved = receiver_ty.clone().lookup_method(self.db, method_name); 1337 let resolved = receiver_ty.clone().lookup_method(self.db, method_name);
1345 let method_ty = match resolved { 1338 let method_ty = match resolved {
1346 Some(func) => { 1339 Some(func) => {
1347 self.write_method_resolution(expr, func); 1340 self.write_method_resolution(tgt_expr, func);
1348 self.db.type_for_def(func.into()) 1341 self.db.type_for_def(func.into())
1349 } 1342 }
1350 None => Ty::Unknown, 1343 None => Ty::Unknown,
@@ -1389,7 +1382,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
1389 1382
1390 expected.ty 1383 expected.ty
1391 } 1384 }
1392 Expr::Path(p) => self.infer_path_expr(expr, p).unwrap_or(Ty::Unknown), 1385 Expr::Path(p) => self.infer_path_expr(tgt_expr, p).unwrap_or(Ty::Unknown),
1393 Expr::Continue => Ty::Never, 1386 Expr::Continue => Ty::Never,
1394 Expr::Break { expr } => { 1387 Expr::Break { expr } => {
1395 if let Some(expr) = expr { 1388 if let Some(expr) = expr {
@@ -1436,9 +1429,10 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
1436 def_id: AdtDef::Struct(s), 1429 def_id: AdtDef::Struct(s),
1437 ref substs, 1430 ref substs,
1438 .. 1431 ..
1439 } => s 1432 } => s.field(self.db, name).map(|field| {
1440 .field(self.db, name) 1433 self.write_field_resolution(tgt_expr, field);
1441 .map(|field| field.ty(self.db).subst(substs)), 1434 field.ty(self.db).subst(substs)
1435 }),
1442 _ => None, 1436 _ => None,
1443 }) 1437 })
1444 .unwrap_or(Ty::Unknown); 1438 .unwrap_or(Ty::Unknown);
@@ -1545,7 +1539,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
1545 let ty = self.insert_type_vars_shallow(ty); 1539 let ty = self.insert_type_vars_shallow(ty);
1546 self.unify(&ty, &expected.ty); 1540 self.unify(&ty, &expected.ty);
1547 let ty = self.resolve_ty_as_possible(ty); 1541 let ty = self.resolve_ty_as_possible(ty);
1548 self.write_expr_ty(expr, ty.clone()); 1542 self.write_expr_ty(tgt_expr, ty.clone());
1549 ty 1543 ty
1550 } 1544 }
1551 1545
diff --git a/crates/ra_hir/src/ty/snapshots/tests__bug_651.snap b/crates/ra_hir/src/ty/snapshots/tests__bug_651.snap
new file mode 100644
index 000000000..d23d3f139
--- /dev/null
+++ b/crates/ra_hir/src/ty/snapshots/tests__bug_651.snap
@@ -0,0 +1,13 @@
1---
2created: "2019-01-25T20:31:47.275112244+00:00"
3creator: [email protected]
4expression: "&result"
5source: crates/ra_hir/src/ty/tests.rs
6---
7[11; 41) '{ ...+ y; }': ()
8[21; 22) 'y': i32
9[25; 27) '92': i32
10[33; 34) '1': i32
11[33; 38) '1 + y': i32
12[37; 38) 'y': i32
13
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index 92c74cf00..e0b0689f8 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -1,7 +1,7 @@
1use std::sync::Arc; 1use std::sync::Arc;
2use std::fmt::Write; 2use std::fmt::Write;
3 3
4use ra_db::{SyntaxDatabase, salsa::Database}; 4use ra_db::{SourceDatabase, salsa::Database};
5use ra_syntax::ast::{self, AstNode}; 5use ra_syntax::ast::{self, AstNode};
6 6
7use crate::{ 7use crate::{
@@ -532,9 +532,22 @@ fn test() {
532 ); 532 );
533} 533}
534 534
535#[test]
536fn bug_651() {
537 check_inference(
538 "bug_651",
539 r#"
540fn quux() {
541 let y = 92;
542 1 + y;
543}
544"#,
545 );
546}
547
535fn infer(content: &str) -> String { 548fn infer(content: &str) -> String {
536 let (db, _, file_id) = MockDatabase::with_single_file(content); 549 let (db, _, file_id) = MockDatabase::with_single_file(content);
537 let source_file = db.source_file(file_id); 550 let source_file = db.parse(file_id);
538 let mut acc = String::new(); 551 let mut acc = String::new();
539 for fn_def in source_file 552 for fn_def in source_file
540 .syntax() 553 .syntax()