]> git.lizzy.rs Git - rust.git/commitdiff
Resolve paths to defs (functions currently) during type inference
authorFlorian Diebold <flodiebold@gmail.com>
Sun, 23 Dec 2018 16:13:11 +0000 (17:13 +0100)
committerFlorian Diebold <flodiebold@gmail.com>
Sun, 23 Dec 2018 16:13:11 +0000 (17:13 +0100)
17 files changed:
Cargo.lock
crates/ra_analysis/src/db.rs
crates/ra_analysis/src/imp.rs
crates/ra_hir/Cargo.toml
crates/ra_hir/src/db.rs
crates/ra_hir/src/function.rs
crates/ra_hir/src/lib.rs
crates/ra_hir/src/mock.rs
crates/ra_hir/src/module.rs
crates/ra_hir/src/module/nameres.rs
crates/ra_hir/src/query_definitions.rs
crates/ra_hir/src/ty.rs
crates/ra_hir/src/ty/tests.rs
crates/ra_hir/src/ty/tests/data/0003_paths.rs [new file with mode: 0644]
crates/ra_hir/src/ty/tests/data/0003_paths.txt [new file with mode: 0644]
crates/ra_syntax/src/ast/generated.rs
crates/ra_syntax/src/grammar.ron

index 5bf946b34cb20c6ae5eaee9c8df1d2c4794c1626..51cf1825d6bf8cac7a12e0005257abb1334bcdd9 100644 (file)
@@ -695,6 +695,7 @@ name = "ra_hir"
 version = "0.1.0"
 dependencies = [
  "arrayvec 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "flexi_logger 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "id-arena 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
index f26c498873ddf9a2d10cb05368e2bdfd573af3ef..780a84291ac106e4c1850cadc93713b48d40e4de 100644 (file)
@@ -94,6 +94,7 @@ impl hir::db::HirDatabase {
             fn fn_syntax() for hir::db::FnSyntaxQuery;
             fn submodules() for hir::db::SubmodulesQuery;
             fn infer() for hir::db::InferQuery;
+            fn type_for_def() for hir::db::TypeForDefQuery;
         }
     }
 }
index f2912d235360908c40f534671281fc7e4ec25d5e..40996bfd738269cab2b3b9cc87c38278df0cc118 100644 (file)
@@ -524,7 +524,7 @@ pub fn type_of(&self, file_id: FileId, range: TextRange) -> Cancelable<Option<St
         let function = ctry!(source_binder::function_from_source(
             &*self.db, file_id, parent_fn
         )?);
-        let infer = function.infer(&*self.db);
+        let infer = function.infer(&*self.db)?;
         Ok(infer.type_of_node(node).map(|t| t.to_string()))
     }
 
index 61650cee9dde17d1119863132e5a4fb25c7dead0..594176337d4b886656bd7977adc865076f80ade6 100644 (file)
@@ -16,3 +16,6 @@ ra_syntax = { path = "../ra_syntax" }
 ra_editor = { path = "../ra_editor" }
 ra_db = { path = "../ra_db" }
 test_utils = { path = "../test_utils" }
+
+[dev-dependencies]
+flexi_logger = "0.10.0"
index f0bff3c02a4589da713847f3a28acbf05768b36b..d94f75857fca5b64b62b4cf89640716ee93e2f8e 100644 (file)
@@ -14,7 +14,7 @@
     function::FnId,
     module::{ModuleId, ModuleTree, ModuleSource,
     nameres::{ItemMap, InputModuleItems}},
-    ty::InferenceResult,
+    ty::{InferenceResult, Ty},
 };
 
 salsa::query_group! {
@@ -31,11 +31,16 @@ fn fn_syntax(fn_id: FnId) -> FnDefNode {
         use fn query_definitions::fn_syntax;
     }
 
-    fn infer(fn_id: FnId) -> Arc<InferenceResult> {
+    fn infer(fn_id: FnId) -> Cancelable<Arc<InferenceResult>> {
         type InferQuery;
         use fn query_definitions::infer;
     }
 
+    fn type_for_def(def_id: DefId) -> Cancelable<Ty> {
+        type TypeForDefQuery;
+        use fn query_definitions::type_for_def;
+    }
+
     fn file_items(file_id: FileId) -> Arc<SourceFileItems> {
         type SourceFileItemsQuery;
         use fn query_definitions::file_items;
index 360e9e9a04ec47bb72b23ac999df95ad3ee792e0..d36477b48d1dbb045fbda5f524d5fcb082fcc7c4 100644 (file)
@@ -5,12 +5,13 @@
     sync::Arc,
 };
 
+use ra_db::Cancelable;
 use ra_syntax::{
     TextRange, TextUnit,
     ast::{self, AstNode, DocCommentsOwner, NameOwner},
 };
 
-use crate::{ DefId, HirDatabase, ty::InferenceResult };
+use crate::{ DefId, HirDatabase, ty::InferenceResult, Module };
 
 pub use self::scope::FnScopes;
 
@@ -18,7 +19,7 @@
 pub struct FnId(pub(crate) DefId);
 
 pub struct Function {
-    fn_id: FnId,
+    pub(crate) fn_id: FnId,
 }
 
 impl Function {
@@ -27,6 +28,10 @@ pub(crate) fn new(def_id: DefId) -> Function {
         Function { fn_id }
     }
 
+    pub fn syntax(&self, db: &impl HirDatabase) -> ast::FnDefNode {
+        db.fn_syntax(self.fn_id)
+    }
+
     pub fn scopes(&self, db: &impl HirDatabase) -> Arc<FnScopes> {
         db.fn_scopes(self.fn_id)
     }
@@ -36,9 +41,14 @@ pub fn signature_info(&self, db: &impl HirDatabase) -> Option<FnSignatureInfo> {
         FnSignatureInfo::new(syntax.borrowed())
     }
 
-    pub fn infer(&self, db: &impl HirDatabase) -> Arc<InferenceResult> {
+    pub fn infer(&self, db: &impl HirDatabase) -> Cancelable<Arc<InferenceResult>> {
         db.infer(self.fn_id)
     }
+
+    pub fn module(&self, db: &impl HirDatabase) -> Cancelable<Module> {
+        let loc = self.fn_id.0.loc(db);
+        Module::new(db, loc.source_root_id, loc.module_id)
+    }
 }
 
 #[derive(Debug, Clone)]
index e84f44675a75eca0b76eec555fa8b2611bfec5f3..a0d99a84dfa556d69b6b52b2554de28a302a64ca 100644 (file)
@@ -29,7 +29,7 @@ macro_rules! ctry {
 
 use std::ops::Index;
 
-use ra_syntax::{SyntaxNodeRef, SyntaxNode};
+use ra_syntax::{SyntaxNodeRef, SyntaxNode, SyntaxKind};
 use ra_db::{LocationIntener, SourceRootId, FileId, Cancelable};
 
 use crate::{
@@ -67,6 +67,23 @@ pub struct DefLoc {
     source_item_id: SourceItemId,
 }
 
+impl DefKind {
+    pub(crate) fn for_syntax_kind(kind: SyntaxKind) -> Option<DefKind> {
+        match kind {
+            SyntaxKind::FN_DEF => Some(DefKind::Function),
+            SyntaxKind::MODULE => Some(DefKind::Module),
+            // These define items, but don't have their own DefKinds yet:
+            SyntaxKind::STRUCT_DEF => Some(DefKind::Item),
+            SyntaxKind::ENUM_DEF => Some(DefKind::Item),
+            SyntaxKind::TRAIT_DEF => Some(DefKind::Item),
+            SyntaxKind::TYPE_DEF => Some(DefKind::Item),
+            SyntaxKind::CONST_DEF => Some(DefKind::Item),
+            SyntaxKind::STATIC_DEF => Some(DefKind::Item),
+            _ => None,
+        }
+    }
+}
+
 impl DefId {
     pub(crate) fn loc(self, db: &impl AsRef<LocationIntener<DefLoc, DefId>>) -> DefLoc {
         db.as_ref().id2loc(self)
index 3020ee793e46633395893629d7ddecb8103eb8fa..b5a99717072ac8835dc10c025287e34a98fc7959 100644 (file)
@@ -192,6 +192,7 @@ impl db::HirDatabase {
             fn fn_syntax() for db::FnSyntaxQuery;
             fn submodules() for db::SubmodulesQuery;
             fn infer() for db::InferQuery;
+            fn type_for_def() for db::TypeForDefQuery;
         }
     }
 }
index cd31e8cfe647c032a988db5b6dafdc287671171e..89111995306d5cca58ee57029c6dfb665f38f725 100644 (file)
@@ -2,6 +2,7 @@
 pub(super) mod nameres;
 
 use std::sync::Arc;
+use log;
 
 use ra_syntax::{
     algo::generate,
index 39e891cda5a6c6a12bc4b10186fb13d73c4c76e0..0b152a406230ab94005589b0afd4dd71c93c70bc 100644 (file)
@@ -272,13 +272,13 @@ fn populate_module(&mut self, module_id: ModuleId, input: &InputModuleItems) ->
                 }
             }
         }
-        // Populate explicitelly declared items, except modules
+        // Populate explicitly declared items, except modules
         for item in input.items.iter() {
             if item.kind == MODULE {
                 continue;
             }
             let def_loc = DefLoc {
-                kind: DefKind::Item,
+                kind: DefKind::for_syntax_kind(item.kind).unwrap_or(DefKind::Item),
                 source_root_id: self.source_root,
                 module_id,
                 source_item_id: SourceItemId {
index ccbfdf02832f32dfb843932b0ffc63bbeabcc926..b654af9204f35fb8b60801d7b23748cc77a8f3bd 100644 (file)
@@ -11,7 +11,7 @@
 use ra_db::{SourceRootId, FileId, Cancelable,};
 
 use crate::{
-    SourceFileItems, SourceItemId, DefKind,
+    SourceFileItems, SourceItemId, DefKind, Function, DefId,
     db::HirDatabase,
     function::{FnScopes, FnId},
     module::{
@@ -19,7 +19,7 @@
         imp::Submodule,
         nameres::{InputModuleItems, ItemMap, Resolver},
     },
-    ty::{self, InferenceResult}
+    ty::{self, InferenceResult, Ty}
 };
 
 /// Resolve `FnId` to the corresponding `SyntaxNode`
@@ -36,11 +36,13 @@ pub(super) fn fn_scopes(db: &impl HirDatabase, fn_id: FnId) -> Arc<FnScopes> {
     Arc::new(res)
 }
 
-pub(super) fn infer(db: &impl HirDatabase, fn_id: FnId) -> Arc<InferenceResult> {
-    let syntax = db.fn_syntax(fn_id);
-    let scopes = db.fn_scopes(fn_id);
-    let res = ty::infer(db, syntax.borrowed(), scopes);
-    Arc::new(res)
+pub(super) fn infer(db: &impl HirDatabase, fn_id: FnId) -> Cancelable<Arc<InferenceResult>> {
+    let function = Function { fn_id };
+    ty::infer(db, function).map(Arc::new)
+}
+
+pub(super) fn type_for_def(db: &impl HirDatabase, def_id: DefId) -> Cancelable<Ty> {
+    ty::type_for_def(db, def_id)
 }
 
 pub(super) fn file_items(db: &impl HirDatabase, file_id: FileId) -> Arc<SourceFileItems> {
index 615a1caed438518bea77dc66a8628a0291bc1065..13ee6cb2750f431b0a2c6871c877910e8f4dbafc 100644 (file)
@@ -5,21 +5,17 @@
 use std::sync::Arc;
 use std::fmt;
 
+use log;
 use rustc_hash::{FxHashMap};
 
-use ra_db::LocalSyntaxPtr;
+use ra_db::{LocalSyntaxPtr, Cancelable};
 use ra_syntax::{
     SmolStr,
     ast::{self, AstNode, LoopBodyOwner, ArgListOwner},
     SyntaxNodeRef
 };
 
-use crate::{
-    FnScopes,
-    db::HirDatabase,
-};
-
-// pub(crate) type TypeId = Id<Ty>;
+use crate::{Def, DefId, FnScopes, Module, Function, Path, db::HirDatabase};
 
 #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
 pub enum Ty {
@@ -65,18 +61,6 @@ pub enum Ty {
     /// `&'a mut T` or `&'a T`.
     // Ref(Region<'tcx>, Ty<'tcx>, hir::Mutability),
 
-    /// The anonymous type of a function declaration/definition. Each
-    /// function has a unique type, which is output (for a function
-    /// named `foo` returning an `i32`) as `fn() -> i32 {foo}`.
-    ///
-    /// For example the type of `bar` here:
-    ///
-    /// ```rust
-    /// fn foo() -> i32 { 1 }
-    /// let bar = foo; // bar: fn() -> i32 {foo}
-    /// ```
-    // FnDef(DefId, &'tcx Substs<'tcx>),
-
     /// A pointer to a function.  Written as `fn() -> i32`.
     ///
     /// For example the type of `bar` here:
@@ -85,7 +69,7 @@ pub enum Ty {
     /// fn foo() -> i32 { 1 }
     /// let bar: fn() -> i32 = foo;
     /// ```
-    // FnPtr(PolyFnSig<'tcx>),
+    FnPtr(Arc<FnSig>),
 
     /// A trait, defined with `trait`.
     // Dynamic(Binder<&'tcx List<ExistentialPredicate<'tcx>>>, ty::Region<'tcx>),
@@ -139,6 +123,12 @@ pub enum Ty {
 
 type TyRef = Arc<Ty>;
 
+#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
+pub struct FnSig {
+    input: Vec<Ty>,
+    output: Ty,
+}
+
 impl Ty {
     pub fn new(node: ast::TypeRef) -> Self {
         use ra_syntax::ast::TypeRef::*;
@@ -208,11 +198,55 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                 }
                 write!(f, ")")
             }
+            Ty::FnPtr(sig) => {
+                write!(f, "fn(")?;
+                for t in &sig.input {
+                    write!(f, "{},", t)?;
+                }
+                write!(f, ") -> {}", sig.output)
+            }
             Ty::Unknown => write!(f, "[unknown]"),
         }
     }
 }
 
+pub fn type_for_fn(db: &impl HirDatabase, f: Function) -> Cancelable<Ty> {
+    eprintln!("type_for_fn {:?}", f.fn_id);
+    let syntax = f.syntax(db);
+    let node = syntax.borrowed();
+    // TODO we ignore type parameters for now
+    let input = node
+        .param_list()
+        .map(|pl| {
+            pl.params()
+                .map(|p| p.type_ref().map(|t| Ty::new(t)).unwrap_or(Ty::Unknown))
+                .collect()
+        })
+        .unwrap_or_else(Vec::new);
+    let output = node
+        .ret_type()
+        .and_then(|rt| rt.type_ref())
+        .map(|t| Ty::new(t))
+        .unwrap_or(Ty::Unknown);
+    let sig = FnSig { input, output };
+    Ok(Ty::FnPtr(Arc::new(sig)))
+}
+
+pub fn type_for_def(db: &impl HirDatabase, def_id: DefId) -> Cancelable<Ty> {
+    let def = def_id.resolve(db)?;
+    match def {
+        Def::Module(..) => {
+            log::debug!("trying to get type for module {:?}", def_id);
+            Ok(Ty::Unknown)
+        }
+        Def::Function(f) => type_for_fn(db, f),
+        Def::Item => {
+            log::debug!("trying to get type for item of unknown type {:?}", def_id);
+            Ok(Ty::Unknown)
+        }
+    }
+}
+
 #[derive(Clone, PartialEq, Eq, Debug)]
 pub struct InferenceResult {
     type_for: FxHashMap<LocalSyntaxPtr, Ty>,
@@ -224,18 +258,22 @@ pub fn type_of_node(&self, node: SyntaxNodeRef) -> Option<Ty> {
     }
 }
 
-#[derive(Clone, PartialEq, Eq, Debug)]
-pub struct InferenceContext {
+#[derive(Clone, Debug)]
+pub struct InferenceContext<'a, D: HirDatabase> {
+    db: &'a D,
     scopes: Arc<FnScopes>,
+    module: Module,
     // TODO unification tables...
     type_for: FxHashMap<LocalSyntaxPtr, Ty>,
 }
 
-impl InferenceContext {
-    fn new(scopes: Arc<FnScopes>) -> Self {
+impl<'a, D: HirDatabase> InferenceContext<'a, D> {
+    fn new(db: &'a D, scopes: Arc<FnScopes>, module: Module) -> Self {
         InferenceContext {
             type_for: FxHashMap::default(),
+            db,
             scopes,
+            module,
         }
     }
 
@@ -262,36 +300,42 @@ fn unify_with_coercion(&mut self, ty1: &Ty, ty2: &Ty) -> Option<Ty> {
         self.unify(ty1, ty2)
     }
 
-    fn infer_path_expr(&mut self, expr: ast::PathExpr) -> Option<Ty> {
-        let p = expr.path()?;
-        if p.qualifier().is_none() {
-            let name = p.segment().and_then(|s| s.name_ref())?;
-            let scope_entry = self.scopes.resolve_local_name(name)?;
-            let ty = self.type_for.get(&scope_entry.ptr())?;
-            Some(ty.clone())
-        } else {
-            // TODO resolve path
-            Some(Ty::Unknown)
-        }
+    fn infer_path_expr(&mut self, expr: ast::PathExpr) -> Cancelable<Option<Ty>> {
+        let ast_path = ctry!(expr.path());
+        let path = ctry!(Path::from_ast(ast_path));
+        if path.is_ident() {
+            // resolve locally
+            let name = ctry!(ast_path.segment().and_then(|s| s.name_ref()));
+            if let Some(scope_entry) = self.scopes.resolve_local_name(name) {
+                let ty = ctry!(self.type_for.get(&scope_entry.ptr()));
+                return Ok(Some(ty.clone()));
+            };
+        };
+
+        // resolve in module
+        let resolved = ctry!(self.module.resolve_path(self.db, path)?);
+        let ty = self.db.type_for_def(resolved)?;
+        // TODO we will need to add type variables for type parameters etc. here
+        Ok(Some(ty))
     }
 
-    fn infer_expr(&mut self, expr: ast::Expr) -> Ty {
+    fn infer_expr(&mut self, expr: ast::Expr) -> Cancelable<Ty> {
         let ty = match expr {
             ast::Expr::IfExpr(e) => {
                 if let Some(condition) = e.condition() {
                     if let Some(e) = condition.expr() {
                         // TODO if no pat, this should be bool
-                        self.infer_expr(e);
+                        self.infer_expr(e)?;
                     }
                     // TODO write type for pat
                 };
                 let if_ty = if let Some(block) = e.then_branch() {
-                    self.infer_block(block)
+                    self.infer_block(block)?
                 } else {
                     Ty::Unknown
                 };
                 let else_ty = if let Some(block) = e.else_branch() {
-                    self.infer_block(block)
+                    self.infer_block(block)?
                 } else {
                     Ty::Unknown
                 };
@@ -304,14 +348,14 @@ fn infer_expr(&mut self, expr: ast::Expr) -> Ty {
             }
             ast::Expr::BlockExpr(e) => {
                 if let Some(block) = e.block() {
-                    self.infer_block(block)
+                    self.infer_block(block)?
                 } else {
                     Ty::Unknown
                 }
             }
             ast::Expr::LoopExpr(e) => {
                 if let Some(block) = e.loop_body() {
-                    self.infer_block(block);
+                    self.infer_block(block)?;
                 };
                 // TODO never, or the type of the break param
                 Ty::Unknown
@@ -320,59 +364,69 @@ fn infer_expr(&mut self, expr: ast::Expr) -> Ty {
                 if let Some(condition) = e.condition() {
                     if let Some(e) = condition.expr() {
                         // TODO if no pat, this should be bool
-                        self.infer_expr(e);
+                        self.infer_expr(e)?;
                     }
                     // TODO write type for pat
                 };
                 if let Some(block) = e.loop_body() {
                     // TODO
-                    self.infer_block(block);
+                    self.infer_block(block)?;
                 };
                 // TODO always unit?
                 Ty::Unknown
             }
             ast::Expr::ForExpr(e) => {
                 if let Some(expr) = e.iterable() {
-                    self.infer_expr(expr);
+                    self.infer_expr(expr)?;
                 }
                 if let Some(_pat) = e.pat() {
                     // TODO write type for pat
                 }
                 if let Some(block) = e.loop_body() {
-                    self.infer_block(block);
+                    self.infer_block(block)?;
                 }
                 // TODO always unit?
                 Ty::Unknown
             }
             ast::Expr::LambdaExpr(e) => {
                 let _body_ty = if let Some(body) = e.body() {
-                    self.infer_expr(body)
+                    self.infer_expr(body)?
                 } else {
                     Ty::Unknown
                 };
                 Ty::Unknown
             }
             ast::Expr::CallExpr(e) => {
+                let _callee_ty = if let Some(e) = e.expr() {
+                    self.infer_expr(e)?
+                } else {
+                    Ty::Unknown
+                };
                 if let Some(arg_list) = e.arg_list() {
                     for arg in arg_list.args() {
                         // TODO unify / expect argument type
-                        self.infer_expr(arg);
+                        self.infer_expr(arg)?;
                     }
                 }
                 Ty::Unknown
             }
             ast::Expr::MethodCallExpr(e) => {
+                let _receiver_ty = if let Some(e) = e.expr() {
+                    self.infer_expr(e)?
+                } else {
+                    Ty::Unknown
+                };
                 if let Some(arg_list) = e.arg_list() {
                     for arg in arg_list.args() {
                         // TODO unify / expect argument type
-                        self.infer_expr(arg);
+                        self.infer_expr(arg)?;
                     }
                 }
                 Ty::Unknown
             }
             ast::Expr::MatchExpr(e) => {
                 let _ty = if let Some(match_expr) = e.expr() {
-                    self.infer_expr(match_expr)
+                    self.infer_expr(match_expr)?
                 } else {
                     Ty::Unknown
                 };
@@ -381,7 +435,7 @@ fn infer_expr(&mut self, expr: ast::Expr) -> Ty {
                         // TODO type the bindings in pat
                         // TODO type the guard
                         let _ty = if let Some(e) = arm.expr() {
-                            self.infer_expr(e)
+                            self.infer_expr(e)?
                         } else {
                             Ty::Unknown
                         };
@@ -394,12 +448,12 @@ fn infer_expr(&mut self, expr: ast::Expr) -> Ty {
             }
             ast::Expr::TupleExpr(_e) => Ty::Unknown,
             ast::Expr::ArrayExpr(_e) => Ty::Unknown,
-            ast::Expr::PathExpr(e) => self.infer_path_expr(e).unwrap_or(Ty::Unknown),
+            ast::Expr::PathExpr(e) => self.infer_path_expr(e)?.unwrap_or(Ty::Unknown),
             ast::Expr::ContinueExpr(_e) => Ty::Never,
             ast::Expr::BreakExpr(_e) => Ty::Never,
             ast::Expr::ParenExpr(e) => {
                 if let Some(e) = e.expr() {
-                    self.infer_expr(e)
+                    self.infer_expr(e)?
                 } else {
                     Ty::Unknown
                 }
@@ -408,7 +462,7 @@ fn infer_expr(&mut self, expr: ast::Expr) -> Ty {
             ast::Expr::ReturnExpr(e) => {
                 if let Some(e) = e.expr() {
                     // TODO unify with return type
-                    self.infer_expr(e);
+                    self.infer_expr(e)?;
                 };
                 Ty::Never
             }
@@ -425,7 +479,7 @@ fn infer_expr(&mut self, expr: ast::Expr) -> Ty {
             ast::Expr::FieldExpr(_e) => Ty::Unknown,
             ast::Expr::TryExpr(e) => {
                 let _inner_ty = if let Some(e) = e.expr() {
-                    self.infer_expr(e)
+                    self.infer_expr(e)?
                 } else {
                     Ty::Unknown
                 };
@@ -433,7 +487,7 @@ fn infer_expr(&mut self, expr: ast::Expr) -> Ty {
             }
             ast::Expr::CastExpr(e) => {
                 let _inner_ty = if let Some(e) = e.expr() {
-                    self.infer_expr(e)
+                    self.infer_expr(e)?
                 } else {
                     Ty::Unknown
                 };
@@ -443,7 +497,7 @@ fn infer_expr(&mut self, expr: ast::Expr) -> Ty {
             }
             ast::Expr::RefExpr(e) => {
                 let _inner_ty = if let Some(e) = e.expr() {
-                    self.infer_expr(e)
+                    self.infer_expr(e)?
                 } else {
                     Ty::Unknown
                 };
@@ -451,7 +505,7 @@ fn infer_expr(&mut self, expr: ast::Expr) -> Ty {
             }
             ast::Expr::PrefixExpr(e) => {
                 let _inner_ty = if let Some(e) = e.expr() {
-                    self.infer_expr(e)
+                    self.infer_expr(e)?
                 } else {
                     Ty::Unknown
                 };
@@ -462,10 +516,10 @@ fn infer_expr(&mut self, expr: ast::Expr) -> Ty {
             ast::Expr::Literal(_e) => Ty::Unknown,
         };
         self.write_ty(expr.syntax(), ty.clone());
-        ty
+        Ok(ty)
     }
 
-    fn infer_block(&mut self, node: ast::Block) -> Ty {
+    fn infer_block(&mut self, node: ast::Block) -> Cancelable<Ty> {
         for stmt in node.statements() {
             match stmt {
                 ast::Stmt::LetStmt(stmt) => {
@@ -476,7 +530,7 @@ fn infer_block(&mut self, node: ast::Block) -> Ty {
                     };
                     let ty = if let Some(expr) = stmt.initializer() {
                         // TODO pass expectation
-                        let expr_ty = self.infer_expr(expr);
+                        let expr_ty = self.infer_expr(expr)?;
                         self.unify_with_coercion(&expr_ty, &decl_ty)
                             .unwrap_or(decl_ty)
                     } else {
@@ -489,23 +543,28 @@ fn infer_block(&mut self, node: ast::Block) -> Ty {
                 }
                 ast::Stmt::ExprStmt(expr_stmt) => {
                     if let Some(expr) = expr_stmt.expr() {
-                        self.infer_expr(expr);
+                        self.infer_expr(expr)?;
                     }
                 }
             }
         }
         let ty = if let Some(expr) = node.expr() {
-            self.infer_expr(expr)
+            self.infer_expr(expr)?
         } else {
             Ty::unit()
         };
         self.write_ty(node.syntax(), ty.clone());
-        ty
+        Ok(ty)
     }
 }
 
-pub fn infer(_db: &impl HirDatabase, node: ast::FnDef, scopes: Arc<FnScopes>) -> InferenceResult {
-    let mut ctx = InferenceContext::new(scopes);
+pub fn infer(db: &impl HirDatabase, function: Function) -> Cancelable<InferenceResult> {
+    let scopes = function.scopes(db);
+    let module = function.module(db)?;
+    let mut ctx = InferenceContext::new(db, scopes, module);
+
+    let syntax = function.syntax(db);
+    let node = syntax.borrowed();
 
     if let Some(param_list) = node.param_list() {
         for param in param_list.params() {
@@ -529,12 +588,12 @@ pub fn infer(_db: &impl HirDatabase, node: ast::FnDef, scopes: Arc<FnScopes>) ->
     // (see Expectation in rustc_typeck)
 
     if let Some(block) = node.body() {
-        ctx.infer_block(block);
+        ctx.infer_block(block)?;
     }
 
     // TODO 'resolve' the types: replace inference variables by their inferred results
 
-    InferenceResult {
+    Ok(InferenceResult {
         type_for: ctx.type_for,
-    }
+    })
 }
index 0880b51bc7cb6623765259a455c626999bde8e03..e0458327ae6f1c1c24069307938d2e643b33ee6d 100644 (file)
@@ -1,5 +1,8 @@
 use std::fmt::Write;
 use std::path::{PathBuf};
+use std::sync::Once;
+
+use flexi_logger::Logger;
 
 use ra_db::{SyntaxDatabase};
 use ra_syntax::ast::{self, AstNode};
@@ -22,7 +25,7 @@ fn infer_file(content: &str) -> String {
         let func = source_binder::function_from_source(&db, file_id, fn_def)
             .unwrap()
             .unwrap();
-        let inference_result = func.infer(&db);
+        let inference_result = func.infer(&db).unwrap();
         for (syntax_ptr, ty) in &inference_result.type_for {
             let node = syntax_ptr.resolve(&source_file);
             write!(
@@ -58,6 +61,8 @@ fn ellipsize(mut text: String, max_len: usize) -> String {
 
 #[test]
 pub fn infer_tests() {
+    static INIT: Once = Once::new();
+    INIT.call_once(|| Logger::with_env().start().unwrap());
     dir_tests(&test_data_dir(), &["."], |text, _path| infer_file(text));
 }
 
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 (file)
index 0000000..e8b1119
--- /dev/null
@@ -0,0 +1,10 @@
+fn a() -> u32 { 1 }
+
+mod b {
+    fn c() -> u32 { 1 }
+}
+
+fn test() {
+    a();
+    b::c();
+}
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 (file)
index 0000000..3a53370
--- /dev/null
@@ -0,0 +1,9 @@
+[16; 17) '1': [unknown]
+[14; 19) '{ 1 }': [unknown]
+[47; 52) '{ 1 }': [unknown]
+[49; 50) '1': [unknown]
+[81; 87) 'b::c()': [unknown]
+[66; 90) '{     ...c(); }': ()
+[72; 73) 'a': fn() -> u32
+[72; 75) 'a()': [unknown]
+[81; 85) 'b::c': fn() -> u32
index b15c4ef6f0773266db32543fbe03fde06632187c..c735338619aa09b3a784b2c1d42538e1c5c341b0 100644 (file)
@@ -3083,7 +3083,11 @@ pub fn owned(&self) -> RetTypeNode {
 }
 
 
-impl<'a> RetType<'a> {}
+impl<'a> RetType<'a> {
+    pub fn type_ref(self) -> Option<TypeRef<'a>> {
+        super::child_opt(self)
+    }
+}
 
 // ReturnExpr
 #[derive(Debug, Clone, Copy,)]
index 8dca493ee3a1779f1f9a789dda2aed5914aa3b32..e3b9032a0c6eb45ddf49168efcfc771865fcfd48 100644 (file)
@@ -254,7 +254,7 @@ Grammar(
             ],
             options: [ "ParamList", ["body", "Block"], "RetType" ],
         ),
-        "RetType": (),
+        "RetType": (options: ["TypeRef"]),
         "StructDef": (
             traits: [
                 "NameOwner",