aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir/src')
-rw-r--r--crates/ra_hir/src/db.rs9
-rw-r--r--crates/ra_hir/src/function.rs16
-rw-r--r--crates/ra_hir/src/lib.rs19
-rw-r--r--crates/ra_hir/src/mock.rs1
-rw-r--r--crates/ra_hir/src/module.rs1
-rw-r--r--crates/ra_hir/src/module/nameres.rs4
-rw-r--r--crates/ra_hir/src/query_definitions.rs16
-rw-r--r--crates/ra_hir/src/ty.rs195
-rw-r--r--crates/ra_hir/src/ty/tests.rs7
-rw-r--r--crates/ra_hir/src/ty/tests/data/0003_paths.rs10
-rw-r--r--crates/ra_hir/src/ty/tests/data/0003_paths.txt9
11 files changed, 203 insertions, 84 deletions
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs
index f0bff3c02..d94f75857 100644
--- a/crates/ra_hir/src/db.rs
+++ b/crates/ra_hir/src/db.rs
@@ -14,7 +14,7 @@ use crate::{
14 function::FnId, 14 function::FnId,
15 module::{ModuleId, ModuleTree, ModuleSource, 15 module::{ModuleId, ModuleTree, ModuleSource,
16 nameres::{ItemMap, InputModuleItems}}, 16 nameres::{ItemMap, InputModuleItems}},
17 ty::InferenceResult, 17 ty::{InferenceResult, Ty},
18}; 18};
19 19
20salsa::query_group! { 20salsa::query_group! {
@@ -31,11 +31,16 @@ pub trait HirDatabase: SyntaxDatabase
31 use fn query_definitions::fn_syntax; 31 use fn query_definitions::fn_syntax;
32 } 32 }
33 33
34 fn infer(fn_id: FnId) -> Arc<InferenceResult> { 34 fn infer(fn_id: FnId) -> Cancelable<Arc<InferenceResult>> {
35 type InferQuery; 35 type InferQuery;
36 use fn query_definitions::infer; 36 use fn query_definitions::infer;
37 } 37 }
38 38
39 fn type_for_def(def_id: DefId) -> Cancelable<Ty> {
40 type TypeForDefQuery;
41 use fn query_definitions::type_for_def;
42 }
43
39 fn file_items(file_id: FileId) -> Arc<SourceFileItems> { 44 fn file_items(file_id: FileId) -> Arc<SourceFileItems> {
40 type SourceFileItemsQuery; 45 type SourceFileItemsQuery;
41 use fn query_definitions::file_items; 46 use fn query_definitions::file_items;
diff --git a/crates/ra_hir/src/function.rs b/crates/ra_hir/src/function.rs
index 360e9e9a0..d36477b48 100644
--- a/crates/ra_hir/src/function.rs
+++ b/crates/ra_hir/src/function.rs
@@ -5,12 +5,13 @@ use std::{
5 sync::Arc, 5 sync::Arc,
6}; 6};
7 7
8use ra_db::Cancelable;
8use ra_syntax::{ 9use ra_syntax::{
9 TextRange, TextUnit, 10 TextRange, TextUnit,
10 ast::{self, AstNode, DocCommentsOwner, NameOwner}, 11 ast::{self, AstNode, DocCommentsOwner, NameOwner},
11}; 12};
12 13
13use crate::{ DefId, HirDatabase, ty::InferenceResult }; 14use crate::{ DefId, HirDatabase, ty::InferenceResult, Module };
14 15
15pub use self::scope::FnScopes; 16pub use self::scope::FnScopes;
16 17
@@ -18,7 +19,7 @@ pub use self::scope::FnScopes;
18pub struct FnId(pub(crate) DefId); 19pub struct FnId(pub(crate) DefId);
19 20
20pub struct Function { 21pub struct Function {
21 fn_id: FnId, 22 pub(crate) fn_id: FnId,
22} 23}
23 24
24impl Function { 25impl Function {
@@ -27,6 +28,10 @@ impl Function {
27 Function { fn_id } 28 Function { fn_id }
28 } 29 }
29 30
31 pub fn syntax(&self, db: &impl HirDatabase) -> ast::FnDefNode {
32 db.fn_syntax(self.fn_id)
33 }
34
30 pub fn scopes(&self, db: &impl HirDatabase) -> Arc<FnScopes> { 35 pub fn scopes(&self, db: &impl HirDatabase) -> Arc<FnScopes> {
31 db.fn_scopes(self.fn_id) 36 db.fn_scopes(self.fn_id)
32 } 37 }
@@ -36,9 +41,14 @@ impl Function {
36 FnSignatureInfo::new(syntax.borrowed()) 41 FnSignatureInfo::new(syntax.borrowed())
37 } 42 }
38 43
39 pub fn infer(&self, db: &impl HirDatabase) -> Arc<InferenceResult> { 44 pub fn infer(&self, db: &impl HirDatabase) -> Cancelable<Arc<InferenceResult>> {
40 db.infer(self.fn_id) 45 db.infer(self.fn_id)
41 } 46 }
47
48 pub fn module(&self, db: &impl HirDatabase) -> Cancelable<Module> {
49 let loc = self.fn_id.0.loc(db);
50 Module::new(db, loc.source_root_id, loc.module_id)
51 }
42} 52}
43 53
44#[derive(Debug, Clone)] 54#[derive(Debug, Clone)]
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs
index e84f44675..a0d99a84d 100644
--- a/crates/ra_hir/src/lib.rs
+++ b/crates/ra_hir/src/lib.rs
@@ -29,7 +29,7 @@ mod ty;
29 29
30use std::ops::Index; 30use std::ops::Index;
31 31
32use ra_syntax::{SyntaxNodeRef, SyntaxNode}; 32use ra_syntax::{SyntaxNodeRef, SyntaxNode, SyntaxKind};
33use ra_db::{LocationIntener, SourceRootId, FileId, Cancelable}; 33use ra_db::{LocationIntener, SourceRootId, FileId, Cancelable};
34 34
35use crate::{ 35use crate::{
@@ -67,6 +67,23 @@ pub struct DefLoc {
67 source_item_id: SourceItemId, 67 source_item_id: SourceItemId,
68} 68}
69 69
70impl DefKind {
71 pub(crate) fn for_syntax_kind(kind: SyntaxKind) -> Option<DefKind> {
72 match kind {
73 SyntaxKind::FN_DEF => Some(DefKind::Function),
74 SyntaxKind::MODULE => Some(DefKind::Module),
75 // These define items, but don't have their own DefKinds yet:
76 SyntaxKind::STRUCT_DEF => Some(DefKind::Item),
77 SyntaxKind::ENUM_DEF => Some(DefKind::Item),
78 SyntaxKind::TRAIT_DEF => Some(DefKind::Item),
79 SyntaxKind::TYPE_DEF => Some(DefKind::Item),
80 SyntaxKind::CONST_DEF => Some(DefKind::Item),
81 SyntaxKind::STATIC_DEF => Some(DefKind::Item),
82 _ => None,
83 }
84 }
85}
86
70impl DefId { 87impl DefId {
71 pub(crate) fn loc(self, db: &impl AsRef<LocationIntener<DefLoc, DefId>>) -> DefLoc { 88 pub(crate) fn loc(self, db: &impl AsRef<LocationIntener<DefLoc, DefId>>) -> DefLoc {
72 db.as_ref().id2loc(self) 89 db.as_ref().id2loc(self)
diff --git a/crates/ra_hir/src/mock.rs b/crates/ra_hir/src/mock.rs
index 3020ee793..b5a997170 100644
--- a/crates/ra_hir/src/mock.rs
+++ b/crates/ra_hir/src/mock.rs
@@ -192,6 +192,7 @@ salsa::database_storage! {
192 fn fn_syntax() for db::FnSyntaxQuery; 192 fn fn_syntax() for db::FnSyntaxQuery;
193 fn submodules() for db::SubmodulesQuery; 193 fn submodules() for db::SubmodulesQuery;
194 fn infer() for db::InferQuery; 194 fn infer() for db::InferQuery;
195 fn type_for_def() for db::TypeForDefQuery;
195 } 196 }
196 } 197 }
197} 198}
diff --git a/crates/ra_hir/src/module.rs b/crates/ra_hir/src/module.rs
index cd31e8cfe..891119953 100644
--- a/crates/ra_hir/src/module.rs
+++ b/crates/ra_hir/src/module.rs
@@ -2,6 +2,7 @@ pub(super) mod imp;
2pub(super) mod nameres; 2pub(super) mod nameres;
3 3
4use std::sync::Arc; 4use std::sync::Arc;
5use log;
5 6
6use ra_syntax::{ 7use ra_syntax::{
7 algo::generate, 8 algo::generate,
diff --git a/crates/ra_hir/src/module/nameres.rs b/crates/ra_hir/src/module/nameres.rs
index 39e891cda..0b152a406 100644
--- a/crates/ra_hir/src/module/nameres.rs
+++ b/crates/ra_hir/src/module/nameres.rs
@@ -272,13 +272,13 @@ where
272 } 272 }
273 } 273 }
274 } 274 }
275 // Populate explicitelly declared items, except modules 275 // Populate explicitly declared items, except modules
276 for item in input.items.iter() { 276 for item in input.items.iter() {
277 if item.kind == MODULE { 277 if item.kind == MODULE {
278 continue; 278 continue;
279 } 279 }
280 let def_loc = DefLoc { 280 let def_loc = DefLoc {
281 kind: DefKind::Item, 281 kind: DefKind::for_syntax_kind(item.kind).unwrap_or(DefKind::Item),
282 source_root_id: self.source_root, 282 source_root_id: self.source_root,
283 module_id, 283 module_id,
284 source_item_id: SourceItemId { 284 source_item_id: SourceItemId {
diff --git a/crates/ra_hir/src/query_definitions.rs b/crates/ra_hir/src/query_definitions.rs
index ccbfdf028..b654af920 100644
--- a/crates/ra_hir/src/query_definitions.rs
+++ b/crates/ra_hir/src/query_definitions.rs
@@ -11,7 +11,7 @@ use ra_syntax::{
11use ra_db::{SourceRootId, FileId, Cancelable,}; 11use ra_db::{SourceRootId, FileId, Cancelable,};
12 12
13use crate::{ 13use crate::{
14 SourceFileItems, SourceItemId, DefKind, 14 SourceFileItems, SourceItemId, DefKind, Function, DefId,
15 db::HirDatabase, 15 db::HirDatabase,
16 function::{FnScopes, FnId}, 16 function::{FnScopes, FnId},
17 module::{ 17 module::{
@@ -19,7 +19,7 @@ use crate::{
19 imp::Submodule, 19 imp::Submodule,
20 nameres::{InputModuleItems, ItemMap, Resolver}, 20 nameres::{InputModuleItems, ItemMap, Resolver},
21 }, 21 },
22 ty::{self, InferenceResult} 22 ty::{self, InferenceResult, Ty}
23}; 23};
24 24
25/// Resolve `FnId` to the corresponding `SyntaxNode` 25/// Resolve `FnId` to the corresponding `SyntaxNode`
@@ -36,11 +36,13 @@ pub(super) fn fn_scopes(db: &impl HirDatabase, fn_id: FnId) -> Arc<FnScopes> {
36 Arc::new(res) 36 Arc::new(res)
37} 37}
38 38
39pub(super) fn infer(db: &impl HirDatabase, fn_id: FnId) -> Arc<InferenceResult> { 39pub(super) fn infer(db: &impl HirDatabase, fn_id: FnId) -> Cancelable<Arc<InferenceResult>> {
40 let syntax = db.fn_syntax(fn_id); 40 let function = Function { fn_id };
41 let scopes = db.fn_scopes(fn_id); 41 ty::infer(db, function).map(Arc::new)
42 let res = ty::infer(db, syntax.borrowed(), scopes); 42}
43 Arc::new(res) 43
44pub(super) fn type_for_def(db: &impl HirDatabase, def_id: DefId) -> Cancelable<Ty> {
45 ty::type_for_def(db, def_id)
44} 46}
45 47
46pub(super) fn file_items(db: &impl HirDatabase, file_id: FileId) -> Arc<SourceFileItems> { 48pub(super) fn file_items(db: &impl HirDatabase, file_id: FileId) -> Arc<SourceFileItems> {
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs
index 615a1caed..13ee6cb27 100644
--- a/crates/ra_hir/src/ty.rs
+++ b/crates/ra_hir/src/ty.rs
@@ -5,21 +5,17 @@ mod tests;
5use std::sync::Arc; 5use std::sync::Arc;
6use std::fmt; 6use std::fmt;
7 7
8use log;
8use rustc_hash::{FxHashMap}; 9use rustc_hash::{FxHashMap};
9 10
10use ra_db::LocalSyntaxPtr; 11use ra_db::{LocalSyntaxPtr, Cancelable};
11use ra_syntax::{ 12use ra_syntax::{
12 SmolStr, 13 SmolStr,
13 ast::{self, AstNode, LoopBodyOwner, ArgListOwner}, 14 ast::{self, AstNode, LoopBodyOwner, ArgListOwner},
14 SyntaxNodeRef 15 SyntaxNodeRef
15}; 16};
16 17
17use crate::{ 18use crate::{Def, DefId, FnScopes, Module, Function, Path, db::HirDatabase};
18 FnScopes,
19 db::HirDatabase,
20};
21
22// pub(crate) type TypeId = Id<Ty>;
23 19
24#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] 20#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
25pub enum Ty { 21pub enum Ty {
@@ -65,18 +61,6 @@ pub enum Ty {
65 /// `&'a mut T` or `&'a T`. 61 /// `&'a mut T` or `&'a T`.
66 // Ref(Region<'tcx>, Ty<'tcx>, hir::Mutability), 62 // Ref(Region<'tcx>, Ty<'tcx>, hir::Mutability),
67 63
68 /// The anonymous type of a function declaration/definition. Each
69 /// function has a unique type, which is output (for a function
70 /// named `foo` returning an `i32`) as `fn() -> i32 {foo}`.
71 ///
72 /// For example the type of `bar` here:
73 ///
74 /// ```rust
75 /// fn foo() -> i32 { 1 }
76 /// let bar = foo; // bar: fn() -> i32 {foo}
77 /// ```
78 // FnDef(DefId, &'tcx Substs<'tcx>),
79
80 /// A pointer to a function. Written as `fn() -> i32`. 64 /// A pointer to a function. Written as `fn() -> i32`.
81 /// 65 ///
82 /// For example the type of `bar` here: 66 /// For example the type of `bar` here:
@@ -85,7 +69,7 @@ pub enum Ty {
85 /// fn foo() -> i32 { 1 } 69 /// fn foo() -> i32 { 1 }
86 /// let bar: fn() -> i32 = foo; 70 /// let bar: fn() -> i32 = foo;
87 /// ``` 71 /// ```
88 // FnPtr(PolyFnSig<'tcx>), 72 FnPtr(Arc<FnSig>),
89 73
90 /// A trait, defined with `trait`. 74 /// A trait, defined with `trait`.
91 // Dynamic(Binder<&'tcx List<ExistentialPredicate<'tcx>>>, ty::Region<'tcx>), 75 // Dynamic(Binder<&'tcx List<ExistentialPredicate<'tcx>>>, ty::Region<'tcx>),
@@ -139,6 +123,12 @@ pub enum Ty {
139 123
140type TyRef = Arc<Ty>; 124type TyRef = Arc<Ty>;
141 125
126#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
127pub struct FnSig {
128 input: Vec<Ty>,
129 output: Ty,
130}
131
142impl Ty { 132impl Ty {
143 pub fn new(node: ast::TypeRef) -> Self { 133 pub fn new(node: ast::TypeRef) -> Self {
144 use ra_syntax::ast::TypeRef::*; 134 use ra_syntax::ast::TypeRef::*;
@@ -208,11 +198,55 @@ impl fmt::Display for Ty {
208 } 198 }
209 write!(f, ")") 199 write!(f, ")")
210 } 200 }
201 Ty::FnPtr(sig) => {
202 write!(f, "fn(")?;
203 for t in &sig.input {
204 write!(f, "{},", t)?;
205 }
206 write!(f, ") -> {}", sig.output)
207 }
211 Ty::Unknown => write!(f, "[unknown]"), 208 Ty::Unknown => write!(f, "[unknown]"),
212 } 209 }
213 } 210 }
214} 211}
215 212
213pub fn type_for_fn(db: &impl HirDatabase, f: Function) -> Cancelable<Ty> {
214 eprintln!("type_for_fn {:?}", f.fn_id);
215 let syntax = f.syntax(db);
216 let node = syntax.borrowed();
217 // TODO we ignore type parameters for now
218 let input = node
219 .param_list()
220 .map(|pl| {
221 pl.params()
222 .map(|p| p.type_ref().map(|t| Ty::new(t)).unwrap_or(Ty::Unknown))
223 .collect()
224 })
225 .unwrap_or_else(Vec::new);
226 let output = node
227 .ret_type()
228 .and_then(|rt| rt.type_ref())
229 .map(|t| Ty::new(t))
230 .unwrap_or(Ty::Unknown);
231 let sig = FnSig { input, output };
232 Ok(Ty::FnPtr(Arc::new(sig)))
233}
234
235pub fn type_for_def(db: &impl HirDatabase, def_id: DefId) -> Cancelable<Ty> {
236 let def = def_id.resolve(db)?;
237 match def {
238 Def::Module(..) => {
239 log::debug!("trying to get type for module {:?}", def_id);
240 Ok(Ty::Unknown)
241 }
242 Def::Function(f) => type_for_fn(db, f),
243 Def::Item => {
244 log::debug!("trying to get type for item of unknown type {:?}", def_id);
245 Ok(Ty::Unknown)
246 }
247 }
248}
249
216#[derive(Clone, PartialEq, Eq, Debug)] 250#[derive(Clone, PartialEq, Eq, Debug)]
217pub struct InferenceResult { 251pub struct InferenceResult {
218 type_for: FxHashMap<LocalSyntaxPtr, Ty>, 252 type_for: FxHashMap<LocalSyntaxPtr, Ty>,
@@ -224,18 +258,22 @@ impl InferenceResult {
224 } 258 }
225} 259}
226 260
227#[derive(Clone, PartialEq, Eq, Debug)] 261#[derive(Clone, Debug)]
228pub struct InferenceContext { 262pub struct InferenceContext<'a, D: HirDatabase> {
263 db: &'a D,
229 scopes: Arc<FnScopes>, 264 scopes: Arc<FnScopes>,
265 module: Module,
230 // TODO unification tables... 266 // TODO unification tables...
231 type_for: FxHashMap<LocalSyntaxPtr, Ty>, 267 type_for: FxHashMap<LocalSyntaxPtr, Ty>,
232} 268}
233 269
234impl InferenceContext { 270impl<'a, D: HirDatabase> InferenceContext<'a, D> {
235 fn new(scopes: Arc<FnScopes>) -> Self { 271 fn new(db: &'a D, scopes: Arc<FnScopes>, module: Module) -> Self {
236 InferenceContext { 272 InferenceContext {
237 type_for: FxHashMap::default(), 273 type_for: FxHashMap::default(),
274 db,
238 scopes, 275 scopes,
276 module,
239 } 277 }
240 } 278 }
241 279
@@ -262,36 +300,42 @@ impl InferenceContext {
262 self.unify(ty1, ty2) 300 self.unify(ty1, ty2)
263 } 301 }
264 302
265 fn infer_path_expr(&mut self, expr: ast::PathExpr) -> Option<Ty> { 303 fn infer_path_expr(&mut self, expr: ast::PathExpr) -> Cancelable<Option<Ty>> {
266 let p = expr.path()?; 304 let ast_path = ctry!(expr.path());
267 if p.qualifier().is_none() { 305 let path = ctry!(Path::from_ast(ast_path));
268 let name = p.segment().and_then(|s| s.name_ref())?; 306 if path.is_ident() {
269 let scope_entry = self.scopes.resolve_local_name(name)?; 307 // resolve locally
270 let ty = self.type_for.get(&scope_entry.ptr())?; 308 let name = ctry!(ast_path.segment().and_then(|s| s.name_ref()));
271 Some(ty.clone()) 309 if let Some(scope_entry) = self.scopes.resolve_local_name(name) {
272 } else { 310 let ty = ctry!(self.type_for.get(&scope_entry.ptr()));
273 // TODO resolve path 311 return Ok(Some(ty.clone()));
274 Some(Ty::Unknown) 312 };
275 } 313 };
314
315 // resolve in module
316 let resolved = ctry!(self.module.resolve_path(self.db, path)?);
317 let ty = self.db.type_for_def(resolved)?;
318 // TODO we will need to add type variables for type parameters etc. here
319 Ok(Some(ty))
276 } 320 }
277 321
278 fn infer_expr(&mut self, expr: ast::Expr) -> Ty { 322 fn infer_expr(&mut self, expr: ast::Expr) -> Cancelable<Ty> {
279 let ty = match expr { 323 let ty = match expr {
280 ast::Expr::IfExpr(e) => { 324 ast::Expr::IfExpr(e) => {
281 if let Some(condition) = e.condition() { 325 if let Some(condition) = e.condition() {
282 if let Some(e) = condition.expr() { 326 if let Some(e) = condition.expr() {
283 // TODO if no pat, this should be bool 327 // TODO if no pat, this should be bool
284 self.infer_expr(e); 328 self.infer_expr(e)?;
285 } 329 }
286 // TODO write type for pat 330 // TODO write type for pat
287 }; 331 };
288 let if_ty = if let Some(block) = e.then_branch() { 332 let if_ty = if let Some(block) = e.then_branch() {
289 self.infer_block(block) 333 self.infer_block(block)?
290 } else { 334 } else {
291 Ty::Unknown 335 Ty::Unknown
292 }; 336 };
293 let else_ty = if let Some(block) = e.else_branch() { 337 let else_ty = if let Some(block) = e.else_branch() {
294 self.infer_block(block) 338 self.infer_block(block)?
295 } else { 339 } else {
296 Ty::Unknown 340 Ty::Unknown
297 }; 341 };
@@ -304,14 +348,14 @@ impl InferenceContext {
304 } 348 }
305 ast::Expr::BlockExpr(e) => { 349 ast::Expr::BlockExpr(e) => {
306 if let Some(block) = e.block() { 350 if let Some(block) = e.block() {
307 self.infer_block(block) 351 self.infer_block(block)?
308 } else { 352 } else {
309 Ty::Unknown 353 Ty::Unknown
310 } 354 }
311 } 355 }
312 ast::Expr::LoopExpr(e) => { 356 ast::Expr::LoopExpr(e) => {
313 if let Some(block) = e.loop_body() { 357 if let Some(block) = e.loop_body() {
314 self.infer_block(block); 358 self.infer_block(block)?;
315 }; 359 };
316 // TODO never, or the type of the break param 360 // TODO never, or the type of the break param
317 Ty::Unknown 361 Ty::Unknown
@@ -320,59 +364,69 @@ impl InferenceContext {
320 if let Some(condition) = e.condition() { 364 if let Some(condition) = e.condition() {
321 if let Some(e) = condition.expr() { 365 if let Some(e) = condition.expr() {
322 // TODO if no pat, this should be bool 366 // TODO if no pat, this should be bool
323 self.infer_expr(e); 367 self.infer_expr(e)?;
324 } 368 }
325 // TODO write type for pat 369 // TODO write type for pat
326 }; 370 };
327 if let Some(block) = e.loop_body() { 371 if let Some(block) = e.loop_body() {
328 // TODO 372 // TODO
329 self.infer_block(block); 373 self.infer_block(block)?;
330 }; 374 };
331 // TODO always unit? 375 // TODO always unit?
332 Ty::Unknown 376 Ty::Unknown
333 } 377 }
334 ast::Expr::ForExpr(e) => { 378 ast::Expr::ForExpr(e) => {
335 if let Some(expr) = e.iterable() { 379 if let Some(expr) = e.iterable() {
336 self.infer_expr(expr); 380 self.infer_expr(expr)?;
337 } 381 }
338 if let Some(_pat) = e.pat() { 382 if let Some(_pat) = e.pat() {
339 // TODO write type for pat 383 // TODO write type for pat
340 } 384 }
341 if let Some(block) = e.loop_body() { 385 if let Some(block) = e.loop_body() {
342 self.infer_block(block); 386 self.infer_block(block)?;
343 } 387 }
344 // TODO always unit? 388 // TODO always unit?
345 Ty::Unknown 389 Ty::Unknown
346 } 390 }
347 ast::Expr::LambdaExpr(e) => { 391 ast::Expr::LambdaExpr(e) => {
348 let _body_ty = if let Some(body) = e.body() { 392 let _body_ty = if let Some(body) = e.body() {
349 self.infer_expr(body) 393 self.infer_expr(body)?
350 } else { 394 } else {
351 Ty::Unknown 395 Ty::Unknown
352 }; 396 };
353 Ty::Unknown 397 Ty::Unknown
354 } 398 }
355 ast::Expr::CallExpr(e) => { 399 ast::Expr::CallExpr(e) => {
400 let _callee_ty = if let Some(e) = e.expr() {
401 self.infer_expr(e)?
402 } else {
403 Ty::Unknown
404 };
356 if let Some(arg_list) = e.arg_list() { 405 if let Some(arg_list) = e.arg_list() {
357 for arg in arg_list.args() { 406 for arg in arg_list.args() {
358 // TODO unify / expect argument type 407 // TODO unify / expect argument type
359 self.infer_expr(arg); 408 self.infer_expr(arg)?;
360 } 409 }
361 } 410 }
362 Ty::Unknown 411 Ty::Unknown
363 } 412 }
364 ast::Expr::MethodCallExpr(e) => { 413 ast::Expr::MethodCallExpr(e) => {
414 let _receiver_ty = if let Some(e) = e.expr() {
415 self.infer_expr(e)?
416 } else {
417 Ty::Unknown
418 };
365 if let Some(arg_list) = e.arg_list() { 419 if let Some(arg_list) = e.arg_list() {
366 for arg in arg_list.args() { 420 for arg in arg_list.args() {
367 // TODO unify / expect argument type 421 // TODO unify / expect argument type
368 self.infer_expr(arg); 422 self.infer_expr(arg)?;
369 } 423 }
370 } 424 }
371 Ty::Unknown 425 Ty::Unknown
372 } 426 }
373 ast::Expr::MatchExpr(e) => { 427 ast::Expr::MatchExpr(e) => {
374 let _ty = if let Some(match_expr) = e.expr() { 428 let _ty = if let Some(match_expr) = e.expr() {
375 self.infer_expr(match_expr) 429 self.infer_expr(match_expr)?
376 } else { 430 } else {
377 Ty::Unknown 431 Ty::Unknown
378 }; 432 };
@@ -381,7 +435,7 @@ impl InferenceContext {
381 // TODO type the bindings in pat 435 // TODO type the bindings in pat
382 // TODO type the guard 436 // TODO type the guard
383 let _ty = if let Some(e) = arm.expr() { 437 let _ty = if let Some(e) = arm.expr() {
384 self.infer_expr(e) 438 self.infer_expr(e)?
385 } else { 439 } else {
386 Ty::Unknown 440 Ty::Unknown
387 }; 441 };
@@ -394,12 +448,12 @@ impl InferenceContext {
394 } 448 }
395 ast::Expr::TupleExpr(_e) => Ty::Unknown, 449 ast::Expr::TupleExpr(_e) => Ty::Unknown,
396 ast::Expr::ArrayExpr(_e) => Ty::Unknown, 450 ast::Expr::ArrayExpr(_e) => Ty::Unknown,
397 ast::Expr::PathExpr(e) => self.infer_path_expr(e).unwrap_or(Ty::Unknown), 451 ast::Expr::PathExpr(e) => self.infer_path_expr(e)?.unwrap_or(Ty::Unknown),
398 ast::Expr::ContinueExpr(_e) => Ty::Never, 452 ast::Expr::ContinueExpr(_e) => Ty::Never,
399 ast::Expr::BreakExpr(_e) => Ty::Never, 453 ast::Expr::BreakExpr(_e) => Ty::Never,
400 ast::Expr::ParenExpr(e) => { 454 ast::Expr::ParenExpr(e) => {
401 if let Some(e) = e.expr() { 455 if let Some(e) = e.expr() {
402 self.infer_expr(e) 456 self.infer_expr(e)?
403 } else { 457 } else {
404 Ty::Unknown 458 Ty::Unknown
405 } 459 }
@@ -408,7 +462,7 @@ impl InferenceContext {
408 ast::Expr::ReturnExpr(e) => { 462 ast::Expr::ReturnExpr(e) => {
409 if let Some(e) = e.expr() { 463 if let Some(e) = e.expr() {
410 // TODO unify with return type 464 // TODO unify with return type
411 self.infer_expr(e); 465 self.infer_expr(e)?;
412 }; 466 };
413 Ty::Never 467 Ty::Never
414 } 468 }
@@ -425,7 +479,7 @@ impl InferenceContext {
425 ast::Expr::FieldExpr(_e) => Ty::Unknown, 479 ast::Expr::FieldExpr(_e) => Ty::Unknown,
426 ast::Expr::TryExpr(e) => { 480 ast::Expr::TryExpr(e) => {
427 let _inner_ty = if let Some(e) = e.expr() { 481 let _inner_ty = if let Some(e) = e.expr() {
428 self.infer_expr(e) 482 self.infer_expr(e)?
429 } else { 483 } else {
430 Ty::Unknown 484 Ty::Unknown
431 }; 485 };
@@ -433,7 +487,7 @@ impl InferenceContext {
433 } 487 }
434 ast::Expr::CastExpr(e) => { 488 ast::Expr::CastExpr(e) => {
435 let _inner_ty = if let Some(e) = e.expr() { 489 let _inner_ty = if let Some(e) = e.expr() {
436 self.infer_expr(e) 490 self.infer_expr(e)?
437 } else { 491 } else {
438 Ty::Unknown 492 Ty::Unknown
439 }; 493 };
@@ -443,7 +497,7 @@ impl InferenceContext {
443 } 497 }
444 ast::Expr::RefExpr(e) => { 498 ast::Expr::RefExpr(e) => {
445 let _inner_ty = if let Some(e) = e.expr() { 499 let _inner_ty = if let Some(e) = e.expr() {
446 self.infer_expr(e) 500 self.infer_expr(e)?
447 } else { 501 } else {
448 Ty::Unknown 502 Ty::Unknown
449 }; 503 };
@@ -451,7 +505,7 @@ impl InferenceContext {
451 } 505 }
452 ast::Expr::PrefixExpr(e) => { 506 ast::Expr::PrefixExpr(e) => {
453 let _inner_ty = if let Some(e) = e.expr() { 507 let _inner_ty = if let Some(e) = e.expr() {
454 self.infer_expr(e) 508 self.infer_expr(e)?
455 } else { 509 } else {
456 Ty::Unknown 510 Ty::Unknown
457 }; 511 };
@@ -462,10 +516,10 @@ impl InferenceContext {
462 ast::Expr::Literal(_e) => Ty::Unknown, 516 ast::Expr::Literal(_e) => Ty::Unknown,
463 }; 517 };
464 self.write_ty(expr.syntax(), ty.clone()); 518 self.write_ty(expr.syntax(), ty.clone());
465 ty 519 Ok(ty)
466 } 520 }
467 521
468 fn infer_block(&mut self, node: ast::Block) -> Ty { 522 fn infer_block(&mut self, node: ast::Block) -> Cancelable<Ty> {
469 for stmt in node.statements() { 523 for stmt in node.statements() {
470 match stmt { 524 match stmt {
471 ast::Stmt::LetStmt(stmt) => { 525 ast::Stmt::LetStmt(stmt) => {
@@ -476,7 +530,7 @@ impl InferenceContext {
476 }; 530 };
477 let ty = if let Some(expr) = stmt.initializer() { 531 let ty = if let Some(expr) = stmt.initializer() {
478 // TODO pass expectation 532 // TODO pass expectation
479 let expr_ty = self.infer_expr(expr); 533 let expr_ty = self.infer_expr(expr)?;
480 self.unify_with_coercion(&expr_ty, &decl_ty) 534 self.unify_with_coercion(&expr_ty, &decl_ty)
481 .unwrap_or(decl_ty) 535 .unwrap_or(decl_ty)
482 } else { 536 } else {
@@ -489,23 +543,28 @@ impl InferenceContext {
489 } 543 }
490 ast::Stmt::ExprStmt(expr_stmt) => { 544 ast::Stmt::ExprStmt(expr_stmt) => {
491 if let Some(expr) = expr_stmt.expr() { 545 if let Some(expr) = expr_stmt.expr() {
492 self.infer_expr(expr); 546 self.infer_expr(expr)?;
493 } 547 }
494 } 548 }
495 } 549 }
496 } 550 }
497 let ty = if let Some(expr) = node.expr() { 551 let ty = if let Some(expr) = node.expr() {
498 self.infer_expr(expr) 552 self.infer_expr(expr)?
499 } else { 553 } else {
500 Ty::unit() 554 Ty::unit()
501 }; 555 };
502 self.write_ty(node.syntax(), ty.clone()); 556 self.write_ty(node.syntax(), ty.clone());
503 ty 557 Ok(ty)
504 } 558 }
505} 559}
506 560
507pub fn infer(_db: &impl HirDatabase, node: ast::FnDef, scopes: Arc<FnScopes>) -> InferenceResult { 561pub fn infer(db: &impl HirDatabase, function: Function) -> Cancelable<InferenceResult> {
508 let mut ctx = InferenceContext::new(scopes); 562 let scopes = function.scopes(db);
563 let module = function.module(db)?;
564 let mut ctx = InferenceContext::new(db, scopes, module);
565
566 let syntax = function.syntax(db);
567 let node = syntax.borrowed();
509 568
510 if let Some(param_list) = node.param_list() { 569 if let Some(param_list) = node.param_list() {
511 for param in param_list.params() { 570 for param in param_list.params() {
@@ -529,12 +588,12 @@ pub fn infer(_db: &impl HirDatabase, node: ast::FnDef, scopes: Arc<FnScopes>) ->
529 // (see Expectation in rustc_typeck) 588 // (see Expectation in rustc_typeck)
530 589
531 if let Some(block) = node.body() { 590 if let Some(block) = node.body() {
532 ctx.infer_block(block); 591 ctx.infer_block(block)?;
533 } 592 }
534 593
535 // TODO 'resolve' the types: replace inference variables by their inferred results 594 // TODO 'resolve' the types: replace inference variables by their inferred results
536 595
537 InferenceResult { 596 Ok(InferenceResult {
538 type_for: ctx.type_for, 597 type_for: ctx.type_for,
539 } 598 })
540} 599}
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index 0880b51bc..e0458327a 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -1,5 +1,8 @@
1use std::fmt::Write; 1use std::fmt::Write;
2use std::path::{PathBuf}; 2use std::path::{PathBuf};
3use std::sync::Once;
4
5use flexi_logger::Logger;
3 6
4use ra_db::{SyntaxDatabase}; 7use ra_db::{SyntaxDatabase};
5use ra_syntax::ast::{self, AstNode}; 8use ra_syntax::ast::{self, AstNode};
@@ -22,7 +25,7 @@ fn infer_file(content: &str) -> String {
22 let func = source_binder::function_from_source(&db, file_id, fn_def) 25 let func = source_binder::function_from_source(&db, file_id, fn_def)
23 .unwrap() 26 .unwrap()
24 .unwrap(); 27 .unwrap();
25 let inference_result = func.infer(&db); 28 let inference_result = func.infer(&db).unwrap();
26 for (syntax_ptr, ty) in &inference_result.type_for { 29 for (syntax_ptr, ty) in &inference_result.type_for {
27 let node = syntax_ptr.resolve(&source_file); 30 let node = syntax_ptr.resolve(&source_file);
28 write!( 31 write!(
@@ -58,6 +61,8 @@ fn ellipsize(mut text: String, max_len: usize) -> String {
58 61
59#[test] 62#[test]
60pub fn infer_tests() { 63pub fn infer_tests() {
64 static INIT: Once = Once::new();
65 INIT.call_once(|| Logger::with_env().start().unwrap());
61 dir_tests(&test_data_dir(), &["."], |text, _path| infer_file(text)); 66 dir_tests(&test_data_dir(), &["."], |text, _path| infer_file(text));
62} 67}
63 68
diff --git a/crates/ra_hir/src/ty/tests/data/0003_paths.rs b/crates/ra_hir/src/ty/tests/data/0003_paths.rs
new file mode 100644
index 000000000..e8b11198b
--- /dev/null
+++ b/crates/ra_hir/src/ty/tests/data/0003_paths.rs
@@ -0,0 +1,10 @@
1fn a() -> u32 { 1 }
2
3mod b {
4 fn c() -> u32 { 1 }
5}
6
7fn test() {
8 a();
9 b::c();
10}
diff --git a/crates/ra_hir/src/ty/tests/data/0003_paths.txt b/crates/ra_hir/src/ty/tests/data/0003_paths.txt
new file mode 100644
index 000000000..3a53370a2
--- /dev/null
+++ b/crates/ra_hir/src/ty/tests/data/0003_paths.txt
@@ -0,0 +1,9 @@
1[16; 17) '1': [unknown]
2[14; 19) '{ 1 }': [unknown]
3[47; 52) '{ 1 }': [unknown]
4[49; 50) '1': [unknown]
5[81; 87) 'b::c()': [unknown]
6[66; 90) '{ ...c(); }': ()
7[72; 73) 'a': fn() -> u32
8[72; 75) 'a()': [unknown]
9[81; 85) 'b::c': fn() -> u32