Repository: rust-analyzer/rust-analyzer
Pull request #370 (2018-12-30 15:40:51)

Self params & type
This implements type inference for `self`, so field completion for methods taking `self` works now.

 - rename `IMPL_ITEM` to `IMPL_BLOCK` -- rustc calls the methods etc. inside an impl `ImplItem`s, and the impl itself doesn't define an item, so I thought this name was clearer.
 - add HIR for impl blocks -- we collect all impls in a crate at once, so we can go from methods to containing impls, and since we will later also need to find all impls for a certain type (which may be anywhere in the crate, I think?). We could be more lazy here, but I don't know if it's worth the complexity.
 - resolve `self` and `Self` during type inference
 - refactor a bit in ty.rs as well

matklad: > rename IMPL_ITEM to IMPL_BLOCK -

Good name! I remember being confused **a lot** by the fact that libsyntax parser has both `parse_impl_item` and `parse_item_impl` methods :)
matklad: @flodiebold when rebasing this, could you send e7eff8047165638994c51ebcaa5b36f89b2d24a6 as a separate PR first? I think that's the commit that's going to cause large number of conflicts, so it's better to merge is separately.

Patch:
diff --git a/crates/ra_analysis/src/completion/complete_dot.rs b/crates/ra_analysis/src/completion/complete_dot.rs
index f24835d177..031d8b98f2 100644
--- a/crates/ra_analysis/src/completion/complete_dot.rs
+++ b/crates/ra_analysis/src/completion/complete_dot.rs
@@ -72,6 +72,21 @@ mod tests {
         );
     }
 
+    #[test]
+    fn test_struct_field_completion_self() {
+        check_ref_completion(
+            r"
+            struct A { the_field: u32 }
+            impl A {
+                fn foo(self) {
+                    self.<|>
+                }
+            }
+            ",
+            r#"the_field"#,
+        );
+    }
+
     #[test]
     fn test_no_struct_field_completion_for_method_call() {
         check_ref_completion(
diff --git a/crates/ra_analysis/src/db.rs b/crates/ra_analysis/src/db.rs
index d7740f0c4e..5422a400b6 100644
--- a/crates/ra_analysis/src/db.rs
+++ b/crates/ra_analysis/src/db.rs
@@ -105,6 +105,7 @@ salsa::database_storage! {
             fn type_for_field() for hir::db::TypeForFieldQuery;
             fn struct_data() for hir::db::StructDataQuery;
             fn enum_data() for hir::db::EnumDataQuery;
+            fn impls_in_module() for hir::db::ImplsInModuleQuery;
         }
     }
 }
diff --git a/crates/ra_analysis/src/mock_analysis.rs b/crates/ra_analysis/src/mock_analysis.rs
index 9605294046..846c76cfe7 100644
--- a/crates/ra_analysis/src/mock_analysis.rs
+++ b/crates/ra_analysis/src/mock_analysis.rs
@@ -4,7 +4,7 @@ use relative_path::RelativePathBuf;
 use test_utils::{extract_offset, extract_range, parse_fixture, CURSOR_MARKER};
 use ra_db::mock::FileMap;
 
-use crate::{Analysis, AnalysisChange, AnalysisHost, FileId, FilePosition, FileRange, SourceRootId};
+use crate::{Analysis, AnalysisChange, AnalysisHost, CrateGraph, FileId, FilePosition, FileRange, SourceRootId};
 
 /// Mock analysis is used in test to bootstrap an AnalysisHost/Analysis
 /// from a set of in-memory files.
@@ -87,12 +87,17 @@ impl MockAnalysis {
         let source_root = SourceRootId(0);
         let mut change = AnalysisChange::new();
         change.add_root(source_root, true);
+        let mut crate_graph = CrateGraph::default();
         for (path, contents) in self.files.into_iter() {
             assert!(path.starts_with('/'));
             let path = RelativePathBuf::from_path(&path[1..]).unwrap();
             let file_id = file_map.add(path.clone());
+            if path == "/lib.rs" || path == "/main.rs" {
+                crate_graph.add_crate_root(file_id);
+            }
             change.add_file(source_root, file_id, path, Arc::new(contents));
         }
+        change.set_crate_graph(crate_graph);
         // change.set_file_resolver(Arc::new(file_map));
         host.apply_change(change);
         host
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs
index 73a4cdc5c8..58296fc6f3 100644
--- a/crates/ra_hir/src/db.rs
+++ b/crates/ra_hir/src/db.rs
@@ -13,6 +13,7 @@ use crate::{
     nameres::{ItemMap, InputModuleItems}},
     ty::{InferenceResult, Ty},
     adt::{StructData, EnumData},
+    impl_block::ModuleImplBlocks,
 };
 
 salsa::query_group! {
@@ -87,6 +88,11 @@ pub trait HirDatabase: SyntaxDatabase
         type ModuleTreeQuery;
         use fn crate::module::imp::module_tree;
     }
+
+    fn impls_in_module(source_root_id: SourceRootId, module_id: ModuleId) -> Cancelable<Arc<ModuleImplBlocks>> {
+        type ImplsInModuleQuery;
+        use fn crate::impl_block::impls_in_module;
+    }
 }
 
 }
diff --git a/crates/ra_hir/src/function.rs b/crates/ra_hir/src/function.rs
index 5a44132fcc..75ef308ae4 100644
--- a/crates/ra_hir/src/function.rs
+++ b/crates/ra_hir/src/function.rs
@@ -11,11 +11,11 @@ use ra_syntax::{
     ast::{self, AstNode, DocCommentsOwner, NameOwner},
 };
 
-use crate::{DefId, DefKind, HirDatabase, ty::InferenceResult, Module};
+use crate::{DefId, DefKind, HirDatabase, ty::InferenceResult, Module, Crate, impl_block::ImplBlock};
 
 pub use self::scope::FnScopes;
 
-#[derive(Debug)]
+#[derive(Debug, Clone, PartialEq, Eq)]
 pub struct Function {
     def_id: DefId,
 }
@@ -25,6 +25,10 @@ impl Function {
         Function { def_id }
     }
 
+    pub fn def_id(&self) -> DefId {
+        self.def_id
+    }
+
     pub fn syntax(&self, db: &impl HirDatabase) -> ast::FnDefNode {
         let def_loc = self.def_id.loc(db);
         assert!(def_loc.kind == DefKind::Function);
@@ -48,6 +52,15 @@ impl Function {
     pub fn module(&self, db: &impl HirDatabase) -> Cancelable<Module> {
         self.def_id.module(db)
     }
+
+    pub fn krate(&self, db: &impl HirDatabase) -> Cancelable<Option<Crate>> {
+        self.def_id.krate(db)
+    }
+
+    /// The containing impl block, if this is a method.
+    pub fn impl_block(&self, db: &impl HirDatabase) -> Cancelable<Option<ImplBlock>> {
+        self.def_id.impl_block(db)
+    }
 }
 
 #[derive(Debug, Clone)]
diff --git a/crates/ra_hir/src/ids.rs b/crates/ra_hir/src/ids.rs
index 66adacc7d4..4d6378e028 100644
--- a/crates/ra_hir/src/ids.rs
+++ b/crates/ra_hir/src/ids.rs
@@ -2,7 +2,7 @@ use ra_db::{SourceRootId, LocationIntener, Cancelable, FileId};
 use ra_syntax::{SourceFileNode, SyntaxKind, SyntaxNode, SyntaxNodeRef, SourceFile, AstNode, ast};
 use ra_arena::{Arena, RawId, impl_arena_id};
 
-use crate::{HirDatabase, PerNs, ModuleId, Module, Def, Function, Struct, Enum};
+use crate::{HirDatabase, PerNs, ModuleId, Module, Def, Function, Struct, Enum, ImplBlock, Crate};
 
 /// hir makes a heavy use of ids: integer (u32) handlers to various things. You
 /// can think of id as a pointer (but without a lifetime) or a file descriptor
@@ -177,6 +177,18 @@ impl DefId {
         let loc = self.loc(db);
         Module::new(db, loc.source_root_id, loc.module_id)
     }
+
+    /// Returns the containing crate.
+    pub fn krate(&self, db: &impl HirDatabase) -> Cancelable<Option<Crate>> {
+        Ok(self.module(db)?.krate(db))
+    }
+
+    /// Returns the containing impl block, if this is an impl item.
+    pub fn impl_block(self, db: &impl HirDatabase) -> Cancelable<Option<ImplBlock>> {
+        let loc = self.loc(db);
+        let module_impls = db.impls_in_module(loc.source_root_id, loc.module_id)?;
+        Ok(ImplBlock::containing(module_impls, self))
+    }
 }
 
 impl DefLoc {
diff --git a/crates/ra_hir/src/impl_block.rs b/crates/ra_hir/src/impl_block.rs
new file mode 100644
index 0000000000..01afa84c49
--- /dev/null
+++ b/crates/ra_hir/src/impl_block.rs
@@ -0,0 +1,180 @@
+use std::sync::Arc;
+use rustc_hash::FxHashMap;
+
+use ra_arena::{Arena, RawId, impl_arena_id};
+use ra_syntax::ast::{self, AstNode};
+use ra_db::{LocationIntener, Cancelable, SourceRootId};
+
+use crate::{
+    DefId, DefLoc, DefKind, SourceItemId, SourceFileItems,
+    Module, Function,
+    db::HirDatabase,
+    type_ref::TypeRef,
+    module::{ModuleSourceNode, ModuleId},
+};
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct ImplBlock {
+    module_impl_blocks: Arc<ModuleImplBlocks>,
+    impl_id: ImplId,
+}
+
+impl ImplBlock {
+    pub(crate) fn containing(
+        module_impl_blocks: Arc<ModuleImplBlocks>,
+        def_id: DefId,
+    ) -> Option<ImplBlock> {
+        let impl_id = *module_impl_blocks.impls_by_def.get(&def_id)?;
+        Some(ImplBlock {
+            module_impl_blocks,
+            impl_id,
+        })
+    }
+
+    fn impl_data(&self) -> &ImplData {
+        &self.module_impl_blocks.impls[self.impl_id]
+    }
+
+    pub fn target_trait(&self) -> Option<&TypeRef> {
+        self.impl_data().target_trait.as_ref()
+    }
+
+    pub fn target_type(&self) -> &TypeRef {
+        &self.impl_data().target_type
+    }
+
+    pub fn items(&self) -> &[ImplItem] {
+        &self.impl_data().items
+    }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct ImplData {
+    target_trait: Option<TypeRef>,
+    target_type: TypeRef,
+    items: Vec<ImplItem>,
+}
+
+impl ImplData {
+    pub(crate) fn from_ast(
+        db: &impl AsRef<LocationIntener<DefLoc, DefId>>,
+        file_items: &SourceFileItems,
+        module: &Module,
+        node: ast::ImplBlock,
+    ) -> Self {
+        let target_trait = node.target_type().map(TypeRef::from_ast);
+        let target_type = TypeRef::from_ast_opt(node.target_type());
+        let file_id = module.source().file_id();
+        let items = if let Some(item_list) = node.item_list() {
+            item_list
+                .impl_items()
+                .map(|item_node| {
+                    let kind = match item_node {
+                        ast::ImplItem::FnDef(..) => DefKind::Function,
+                        ast::ImplItem::ConstDef(..) => DefKind::Item,
+                        ast::ImplItem::TypeDef(..) => DefKind::Item,
+                    };
+                    let item_id = file_items.id_of_unchecked(item_node.syntax());
+                    let def_loc = DefLoc {
+                        kind,
+                        source_root_id: module.source_root_id,
+                        module_id: module.module_id,
+                        source_item_id: SourceItemId {
+                            file_id,
+                            item_id: Some(item_id),
+                        },
+                    };
+                    let def_id = def_loc.id(db);
+                    match item_node {
+                        ast::ImplItem::FnDef(..) => ImplItem::Method(Function::new(def_id)),
+                        ast::ImplItem::ConstDef(..) => ImplItem::Const(def_id),
+                        ast::ImplItem::TypeDef(..) => ImplItem::Type(def_id),
+                    }
+                })
+                .collect()
+        } else {
+            Vec::new()
+        };
+        ImplData {
+            target_trait,
+            target_type,
+            items,
+        }
+    }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub enum ImplItem {
+    Method(Function),
+    // these don't have their own types yet
+    Const(DefId),
+    Type(DefId),
+    // Existential
+}
+
+impl ImplItem {
+    pub fn def_id(&self) -> DefId {
+        match self {
+            ImplItem::Method(f) => f.def_id(),
+            ImplItem::Const(def_id) => *def_id,
+            ImplItem::Type(def_id) => *def_id,
+        }
+    }
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub struct ImplId(pub RawId);
+impl_arena_id!(ImplId);
+
+/// Collection of impl blocks is a two-step process: First we collect the blocks
+/// per-module; then we build an index of all impl blocks in the crate. This
+/// way, we avoid having to do this process for the whole crate whenever someone
+/// types in any file; as long as the impl blocks in the file don't change, we
+/// don't need to do the second step again.
+///
+/// (The second step does not yet exist currently.)
+#[derive(Debug, PartialEq, Eq)]
+pub struct ModuleImplBlocks {
+    impls: Arena<ImplId, ImplData>,
+    impls_by_def: FxHashMap<DefId, ImplId>,
+}
+
+impl ModuleImplBlocks {
+    fn new() -> Self {
+        ModuleImplBlocks {
+            impls: Arena::default(),
+            impls_by_def: FxHashMap::default(),
+        }
+    }
+
+    fn collect(&mut self, db: &impl HirDatabase, module: Module) -> Cancelable<()> {
+        let module_source_node = module.source().resolve(db);
+        let node = match &module_source_node {
+            ModuleSourceNode::SourceFile(node) => node.borrowed().syntax(),
+            ModuleSourceNode::Module(node) => node.borrowed().syntax(),
+        };
+
+        let source_file_items = db.file_items(module.source().file_id());
+
+        for impl_block_ast in node.children().filter_map(ast::ImplBlock::cast) {
+            let impl_block = ImplData::from_ast(db, &source_file_items, &module, impl_block_ast);
+            let id = self.impls.alloc(impl_block);
+            for impl_item in &self.impls[id].items {
+                self.impls_by_def.insert(impl_item.def_id(), id);
+            }
+        }
+
+        Ok(())
+    }
+}
+
+pub(crate) fn impls_in_module(
+    db: &impl HirDatabase,
+    source_root_id: SourceRootId,
+    module_id: ModuleId,
+) -> Cancelable<Arc<ModuleImplBlocks>> {
+    let mut result = ModuleImplBlocks::new();
+    let module = Module::new(db, source_root_id, module_id)?;
+    result.collect(db, module)?;
+    Ok(Arc::new(result))
+}
diff --git a/crates/ra_hir/src/krate.rs b/crates/ra_hir/src/krate.rs
index a0821d15dd..5194e280b7 100644
--- a/crates/ra_hir/src/krate.rs
+++ b/crates/ra_hir/src/krate.rs
@@ -5,7 +5,7 @@ use crate::{HirDatabase, Module, Name, AsName, HirFileId};
 /// hir::Crate describes a single crate. It's the main inteface with which
 /// crate's dependencies interact. Mostly, it should be just a proxy for the
 /// root module.
-#[derive(Debug)]
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub struct Crate {
     crate_id: CrateId,
 }
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs
index 344b543b6e..2abcec441b 100644
--- a/crates/ra_hir/src/lib.rs
+++ b/crates/ra_hir/src/lib.rs
@@ -31,6 +31,7 @@ mod function;
 mod adt;
 mod type_ref;
 mod ty;
+mod impl_block;
 
 use crate::{
     db::HirDatabase,
@@ -48,6 +49,7 @@ pub use self::{
     function::{Function, FnScopes},
     adt::{Struct, Enum},
     ty::Ty,
+    impl_block::{ImplBlock, ImplItem},
 };
 
 pub use self::function::FnSignatureInfo;
diff --git a/crates/ra_hir/src/mock.rs b/crates/ra_hir/src/mock.rs
index 89b18194ac..a9db932ff0 100644
--- a/crates/ra_hir/src/mock.rs
+++ b/crates/ra_hir/src/mock.rs
@@ -30,6 +30,10 @@ impl MockDatabase {
         let file_id = db.add_file(&mut source_root, "/main.rs", text);
         db.query_mut(ra_db::SourceRootQuery)
             .set(WORKSPACE, Arc::new(source_root.clone()));
+
+        let mut crate_graph = CrateGraph::default();
+        crate_graph.add_crate_root(file_id);
+        db.set_crate_graph(crate_graph);
         (db, source_root, file_id)
     }
 
@@ -203,6 +207,7 @@ salsa::database_storage! {
             fn type_for_field() for db::TypeForFieldQuery;
             fn struct_data() for db::StructDataQuery;
             fn enum_data() for db::EnumDataQuery;
+            fn impls_in_module() for db::ImplsInModuleQuery;
         }
     }
 }
diff --git a/crates/ra_hir/src/module.rs b/crates/ra_hir/src/module.rs
index c70dc54dd9..b9821115ce 100644
--- a/crates/ra_hir/src/module.rs
+++ b/crates/ra_hir/src/module.rs
@@ -71,6 +71,21 @@ impl Module {
         })
     }
 
+    /// Returns an iterator of all children of this module.
+    pub fn children<'a>(&'a self) -> impl Iterator<Item = (Name, Module)> + 'a {
+        self.module_id
+            .children(&self.tree)
+            .map(move |(name, module_id)| {
+                (
+                    name,
+                    Module {
+                        module_id,
+                        ..self.clone()
+                    },
+                )
+            })
+    }
+
     /// Returns the crate this module is part of.
     pub fn krate(&self, db: &impl HirDatabase) -> Option<Crate> {
         let root_id = self.module_id.crate_root(&self.tree);
diff --git a/crates/ra_hir/src/name.rs b/crates/ra_hir/src/name.rs
index 51e8b3da86..017caf442e 100644
--- a/crates/ra_hir/src/name.rs
+++ b/crates/ra_hir/src/name.rs
@@ -51,6 +51,7 @@ impl Name {
             "u128" => KnownName::U128,
             "f32" => KnownName::F32,
             "f64" => KnownName::F64,
+            "Self" => KnownName::Self_,
             _ => return None,
         };
         Some(name)
@@ -84,7 +85,7 @@ impl AsName for ra_db::Dependency {
 // const ISIZE: Name = Name::new("isize")
 // ```
 // but const-fn is not that powerful yet.
-#[derive(Debug)]
+#[derive(Debug, PartialEq, Eq)]
 pub(crate) enum KnownName {
     Isize,
     I8,
@@ -102,4 +103,6 @@ pub(crate) enum KnownName {
 
     F32,
     F64,
+
+    Self_,
 }
diff --git a/crates/ra_hir/src/path.rs b/crates/ra_hir/src/path.rs
index 93f7203fe2..9fdfa0d131 100644
--- a/crates/ra_hir/src/path.rs
+++ b/crates/ra_hir/src/path.rs
@@ -70,6 +70,11 @@ impl Path {
         self.kind == PathKind::Plain && self.segments.len() == 1
     }
 
+    /// `true` if this path is just a standalone `self`
+    pub fn is_self(&self) -> bool {
+        self.kind == PathKind::Self_ && self.segments.len() == 0
+    }
+
     /// If this path is a single identifier, like `foo`, return its name.
     pub fn as_ident(&self) -> Option<&Name> {
         if self.kind != PathKind::Plain || self.segments.len() > 1 {
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs
index 719b3f7cd7..e33762e0dd 100644
--- a/crates/ra_hir/src/ty.rs
+++ b/crates/ra_hir/src/ty.rs
@@ -31,9 +31,10 @@ use ra_syntax::{
 };
 
 use crate::{
-    Def, DefId, FnScopes, Module, Function, Struct, Enum, Path, Name, AsName,
+    Def, DefId, FnScopes, Module, Function, Struct, Enum, Path, Name, AsName, ImplBlock,
     db::HirDatabase,
     type_ref::{TypeRef, Mutability},
+    name::KnownName,
 };
 
 /// The ID of a type variable.
@@ -235,6 +236,7 @@ impl Ty {
     pub(crate) fn from_hir(
         db: &impl HirDatabase,
         module: &Module,
+        impl_block: Option<&ImplBlock>,
         type_ref: &TypeRef,
     ) -> Cancelable<Self> {
         Ok(match type_ref {
@@ -242,29 +244,29 @@ impl Ty {
             TypeRef::Tuple(inner) => {
                 let inner_tys = inner
                     .iter()
-                    .map(|tr| Ty::from_hir(db, module, tr))
+                    .map(|tr| Ty::from_hir(db, module, impl_block, tr))
                     .collect::<Cancelable<Vec<_>>>()?;
                 Ty::Tuple(inner_tys.into())
             }
-            TypeRef::Path(path) => Ty::from_hir_path(db, module, path)?,
+            TypeRef::Path(path) => Ty::from_hir_path(db, module, impl_block, path)?,
             TypeRef::RawPtr(inner, mutability) => {
-                let inner_ty = Ty::from_hir(db, module, inner)?;
+                let inner_ty = Ty::from_hir(db, module, impl_block, inner)?;
                 Ty::RawPtr(Arc::new(inner_ty), *mutability)
             }
             TypeRef::Array(_inner) => Ty::Unknown, // TODO
             TypeRef::Slice(inner) => {
-                let inner_ty = Ty::from_hir(db, module, inner)?;
+                let inner_ty = Ty::from_hir(db, module, impl_block, inner)?;
                 Ty::Slice(Arc::new(inner_ty))
             }
             TypeRef::Reference(inner, mutability) => {
-                let inner_ty = Ty::from_hir(db, module, inner)?;
+                let inner_ty = Ty::from_hir(db, module, impl_block, inner)?;
                 Ty::Ref(Arc::new(inner_ty), *mutability)
             }
             TypeRef::Placeholder => Ty::Unknown,
             TypeRef::Fn(params) => {
                 let mut inner_tys = params
                     .iter()
-                    .map(|tr| Ty::from_hir(db, module, tr))
+                    .map(|tr| Ty::from_hir(db, module, impl_block, tr))
                     .collect::<Cancelable<Vec<_>>>()?;
                 let return_ty = inner_tys
                     .pop()
@@ -279,9 +281,21 @@ impl Ty {
         })
     }
 
+    pub(crate) fn from_hir_opt(
+        db: &impl HirDatabase,
+        module: &Module,
+        impl_block: Option<&ImplBlock>,
+        type_ref: Option<&TypeRef>,
+    ) -> Cancelable<Self> {
+        type_ref
+            .map(|t| Ty::from_hir(db, module, impl_block, t))
+            .unwrap_or(Ok(Ty::Unknown))
+    }
+
     pub(crate) fn from_hir_path(
         db: &impl HirDatabase,
         module: &Module,
+        impl_block: Option<&ImplBlock>,
         path: &Path,
     ) -> Cancelable<Self> {
         if let Some(name) = path.as_ident() {
@@ -291,6 +305,8 @@ impl Ty {
                 return Ok(Ty::Uint(uint_ty));
             } else if let Some(float_ty) = primitive::FloatTy::from_name(name) {
                 return Ok(Ty::Float(float_ty));
+            } else if name.as_known_name() == Some(KnownName::Self_) {
+                return Ty::from_hir_opt(db, module, None, impl_block.map(|i| i.target_type()));
             }
         }
 
@@ -308,18 +324,20 @@ impl Ty {
     pub(crate) fn from_ast_opt(
         db: &impl HirDatabase,
         module: &Module,
+        impl_block: Option<&ImplBlock>,
         node: Option<ast::TypeRef>,
     ) -> Cancelable<Self> {
-        node.map(|n| Ty::from_ast(db, module, n))
+        node.map(|n| Ty::from_ast(db, module, impl_block, n))
             .unwrap_or(Ok(Ty::Unknown))
     }
 
     pub(crate) fn from_ast(
         db: &impl HirDatabase,
         module: &Module,
+        impl_block: Option<&ImplBlock>,
         node: ast::TypeRef,
     ) -> Cancelable<Self> {
-        Ty::from_hir(db, module, &TypeRef::from_ast(node))
+        Ty::from_hir(db, module, impl_block, &TypeRef::from_ast(node))
     }
 
     pub fn unit() -> Self {
@@ -402,18 +420,19 @@ impl fmt::Display for Ty {
 fn type_for_fn(db: &impl HirDatabase, f: Function) -> Cancelable<Ty> {
     let syntax = f.syntax(db);
     let module = f.module(db)?;
+    let impl_block = f.impl_block(db)?;
     let node = syntax.borrowed();
     // TODO we ignore type parameters for now
     let input = node
         .param_list()
         .map(|pl| {
             pl.params()
-                .map(|p| Ty::from_ast_opt(db, &module, p.type_ref()))
+                .map(|p| Ty::from_ast_opt(db, &module, impl_block.as_ref(), p.type_ref()))
                 .collect()
         })
         .unwrap_or_else(|| Ok(Vec::new()))?;
     let output = if let Some(type_ref) = node.ret_type().and_then(|rt| rt.type_ref()) {
-        Ty::from_ast(db, &module, type_ref)?
+        Ty::from_ast(db, &module, impl_block.as_ref(), type_ref)?
     } else {
         Ty::unit()
     };
@@ -467,12 +486,13 @@ pub(super) fn type_for_field(db: &impl HirDatabase, def_id: DefId, field: Name)
         ),
     };
     let module = def_id.module(db)?;
+    let impl_block = def_id.impl_block(db)?;
     let type_ref = if let Some(tr) = variant_data.get_field_type_ref(&field) {
         tr
     } else {
         return Ok(Ty::Unknown);
     };
-    Ty::from_hir(db, &module, &type_ref)
+    Ty::from_hir(db, &module, impl_block.as_ref(), &type_ref)
 }
 
 /// The result of type inference: A mapping from expressions and patterns to types.
@@ -496,19 +516,32 @@ impl InferenceResult {
 struct InferenceContext<'a, D: HirDatabase> {
     db: &'a D,
     scopes: Arc<FnScopes>,
+    /// The self param for the current method, if it exists.
+    self_param: Option<LocalSyntaxPtr>,
     module: Module,
+    impl_block: Option<ImplBlock>,
     var_unification_table: InPlaceUnificationTable<TypeVarId>,
     type_of: FxHashMap<LocalSyntaxPtr, Ty>,
+    /// The return type of the function being inferred.
+    return_ty: Ty,
 }
 
 impl<'a, D: HirDatabase> InferenceContext<'a, D> {
-    fn new(db: &'a D, scopes: Arc<FnScopes>, module: Module) -> Self {
+    fn new(
+        db: &'a D,
+        scopes: Arc<FnScopes>,
+        module: Module,
+        impl_block: Option<ImplBlock>,
+    ) -> Self {
         InferenceContext {
             type_of: FxHashMap::default(),
             var_unification_table: InPlaceUnificationTable::new(),
+            self_param: None,       // set during parameter typing
+            return_ty: Ty::Unknown, // set in collect_fn_signature
             db,
             scopes,
             module,
+            impl_block,
         }
     }
 
@@ -525,6 +558,14 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
         self.type_of.insert(LocalSyntaxPtr::new(node), ty);
     }
 
+    fn make_ty(&self, type_ref: &TypeRef) -> Cancelable<Ty> {
+        Ty::from_hir(self.db, &self.module, self.impl_block.as_ref(), type_ref)
+    }
+
+    fn make_ty_opt(&self, type_ref: Option<&TypeRef>) -> Cancelable<Ty> {
+        Ty::from_hir_opt(self.db, &self.module, self.impl_block.as_ref(), type_ref)
+    }
+
     fn unify(&mut self, ty1: &Ty, ty2: &Ty) -> bool {
         match (ty1, ty2) {
             (Ty::Unknown, ..) => true,
@@ -628,6 +669,12 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
                 let ty = self.resolve_ty_as_possible(ty.clone());
                 return Ok(Some(ty));
             };
+        } else if path.is_self() {
+            // resolve `self` param
+            let self_param = ctry!(self.self_param);
+            let ty = ctry!(self.type_of.get(&self_param));
+            let ty = self.resolve_ty_as_possible(ty.clone());
+            return Ok(Some(ty));
         };
 
         // resolve in module
@@ -826,7 +873,12 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
             }
             ast::Expr::CastExpr(e) => {
                 let _inner_ty = self.infer_expr_opt(e.expr(), &Expectation::none())?;
-                let cast_ty = Ty::from_ast_opt(self.db, &self.module, e.type_ref())?;
+                let cast_ty = Ty::from_ast_opt(
+                    self.db,
+                    &self.module,
+                    self.impl_block.as_ref(),
+                    e.type_ref(),
+                )?;
                 let cast_ty = self.insert_type_vars(cast_ty);
                 // TODO do the coercion...
                 cast_ty
@@ -880,7 +932,12 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
         for stmt in node.statements() {
             match stmt {
                 ast::Stmt::LetStmt(stmt) => {
-                    let decl_ty = Ty::from_ast_opt(self.db, &self.module, stmt.type_ref())?;
+                    let decl_ty = Ty::from_ast_opt(
+                        self.db,
+                        &self.module,
+                        self.impl_block.as_ref(),
+                        stmt.type_ref(),
+                    )?;
                     let decl_ty = self.insert_type_vars(decl_ty);
                     let ty = if let Some(expr) = stmt.initializer() {
                         let expr_ty = self.infer_expr(expr, &Expectation::has_type(decl_ty))?;
@@ -906,46 +963,71 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
         self.write_ty(node.syntax(), ty.clone());
         Ok(ty)
     }
+
+    fn collect_fn_signature(&mut self, node: ast::FnDef) -> Cancelable<()> {
+        if let Some(param_list) = node.param_list() {
+            if let Some(self_param) = param_list.self_param() {
+                let self_type = if let Some(type_ref) = self_param.type_ref() {
+                    let ty = self.make_ty(&TypeRef::from_ast(type_ref))?;
+                    self.insert_type_vars(ty)
+                } else {
+                    // TODO this should be handled by desugaring during HIR conversion
+                    let ty = self.make_ty_opt(self.impl_block.as_ref().map(|i| i.target_type()))?;
+                    let ty = match self_param.flavor() {
+                        ast::SelfParamFlavor::Owned => ty,
+                        ast::SelfParamFlavor::Ref => Ty::Ref(Arc::new(ty), Mutability::Shared),
+                        ast::SelfParamFlavor::MutRef => Ty::Ref(Arc::new(ty), Mutability::Mut),
+                    };
+                    self.insert_type_vars(ty)
+                };
+                if let Some(self_kw) = self_param.self_kw() {
+                    let self_param = LocalSyntaxPtr::new(self_kw.syntax());
+                    self.self_param = Some(self_param);
+                    self.type_of.insert(self_param, self_type);
+                }
+            }
+            for param in param_list.params() {
+                let pat = if let Some(pat) = param.pat() {
+                    pat
+                } else {
+                    continue;
+                };
+                let ty = if let Some(type_ref) = param.type_ref() {
+                    let ty = self.make_ty(&TypeRef::from_ast(type_ref))?;
+                    self.insert_type_vars(ty)
+                } else {
+                    // missing type annotation
+                    self.new_type_var()
+                };
+                self.type_of.insert(LocalSyntaxPtr::new(pat.syntax()), ty);
+            }
+        }
+
+        self.return_ty = if let Some(type_ref) = node.ret_type().and_then(|n| n.type_ref()) {
+            let ty = self.make_ty(&TypeRef::from_ast(type_ref))?;
+            self.insert_type_vars(ty)
+        } else {
+            Ty::unit()
+        };
+
+        Ok(())
+    }
 }
 
 pub fn infer(db: &impl HirDatabase, def_id: DefId) -> Cancelable<Arc<InferenceResult>> {
     let function = Function::new(def_id); // TODO: consts also need inference
     let scopes = function.scopes(db);
     let module = function.module(db)?;
-    let mut ctx = InferenceContext::new(db, scopes, module);
+    let impl_block = function.impl_block(db)?;
+    let mut ctx = InferenceContext::new(db, scopes, module, impl_block);
 
     let syntax = function.syntax(db);
     let node = syntax.borrowed();
 
-    if let Some(param_list) = node.param_list() {
-        for param in param_list.params() {
-            let pat = if let Some(pat) = param.pat() {
-                pat
-            } else {
-                continue;
-            };
-            if let Some(type_ref) = param.type_ref() {
-                let ty = Ty::from_ast(db, &ctx.module, type_ref)?;
-                let ty = ctx.insert_type_vars(ty);
-                ctx.type_of.insert(LocalSyntaxPtr::new(pat.syntax()), ty);
-            } else {
-                // TODO self param
-                let type_var = ctx.new_type_var();
-                ctx.type_of
-                    .insert(LocalSyntaxPtr::new(pat.syntax()), type_var);
-            };
-        }
-    }
-
-    let ret_ty = if let Some(type_ref) = node.ret_type().and_then(|n| n.type_ref()) {
-        let ty = Ty::from_ast(db, &ctx.module, type_ref)?;
-        ctx.insert_type_vars(ty)
-    } else {
-        Ty::unit()
-    };
+    ctx.collect_fn_signature(node)?;
 
     if let Some(block) = node.body() {
-        ctx.infer_block(block, &Expectation::has_type(ret_ty))?;
+        ctx.infer_block(block, &Expectation::has_type(ctx.return_ty.clone()))?;
     }
 
     Ok(Arc::new(ctx.resolve_all()))
diff --git a/crates/ra_syntax/src/ast.rs b/crates/ra_syntax/src/ast.rs
index 7f986d3224..2a3bd27e25 100644
--- a/crates/ra_syntax/src/ast.rs
+++ b/crates/ra_syntax/src/ast.rs
@@ -482,6 +482,37 @@ impl<'a> PrefixExpr<'a> {
     }
 }
 
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
+pub enum SelfParamFlavor {
+    /// self
+    Owned,
+    /// &self
+    Ref,
+    /// &mut self
+    MutRef,
+}
+
+impl<'a> SelfParam<'a> {
+    pub fn flavor(&self) -> SelfParamFlavor {
+        let borrowed = self.syntax().children().any(|n| n.kind() == AMP);
+        if borrowed {
+            // check for a `mut` coming after the & -- `mut &self` != `&mut self`
+            if self
+                .syntax()
+                .children()
+                .skip_while(|n| n.kind() != AMP)
+                .any(|n| n.kind() == MUT_KW)
+            {
+                SelfParamFlavor::MutRef
+            } else {
+                SelfParamFlavor::Ref
+            }
+        } else {
+            SelfParamFlavor::Owned
+        }
+    }
+}
+
 #[test]
 fn test_doc_comment_of_items() {
     let file = SourceFileNode::parse(
diff --git a/crates/ra_syntax/src/ast/generated.rs b/crates/ra_syntax/src/ast/generated.rs
index c1c63f555a..7df6a9c466 100644
--- a/crates/ra_syntax/src/ast/generated.rs
+++ b/crates/ra_syntax/src/ast/generated.rs
@@ -1442,7 +1442,39 @@ impl<R: TreeRoot<RaTypes>> ImplBlockNode<R> {
 }
 
 
-impl<'a> ImplBlock<'a> {}
+impl<'a> ImplBlock<'a> {
+    pub fn item_list(self) -> Option<ItemList<'a>> {
+        super::child_opt(self)
+    }
+}
+
+// ImplItem
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum ImplItem<'a> {
+    FnDef(FnDef<'a>),
+    TypeDef(TypeDef<'a>),
+    ConstDef(ConstDef<'a>),
+}
+
+impl<'a> AstNode<'a> for ImplItem<'a> {
+    fn cast(syntax: SyntaxNodeRef<'a>) -> Option<Self> {
+        match syntax.kind() {
+            FN_DEF => Some(ImplItem::FnDef(FnDef { syntax })),
+            TYPE_DEF => Some(ImplItem::TypeDef(TypeDef { syntax })),
+            CONST_DEF => Some(ImplItem::ConstDef(ConstDef { syntax })),
+            _ => None,
+        }
+    }
+    fn syntax(self) -> SyntaxNodeRef<'a> {
+        match self {
+            ImplItem::FnDef(inner) => inner.syntax(),
+            ImplItem::TypeDef(inner) => inner.syntax(),
+            ImplItem::ConstDef(inner) => inner.syntax(),
+        }
+    }
+}
+
+impl<'a> ImplItem<'a> {}
 
 // ImplTraitType
 #[derive(Debug, Clone, Copy,)]
@@ -1555,7 +1587,11 @@ impl<R: TreeRoot<RaTypes>> ItemListNode<R> {
 
 impl<'a> ast::FnDefOwner<'a> for ItemList<'a> {}
 impl<'a> ast::ModuleItemOwner<'a> for ItemList<'a> {}
-impl<'a> ItemList<'a> {}
+impl<'a> ItemList<'a> {
+    pub fn impl_items(self) -> impl Iterator<Item = ImplItem<'a>> + 'a {
+        super::children(self)
+    }
+}
 
 // Label
 #[derive(Debug, Clone, Copy,)]
@@ -3452,6 +3488,43 @@ impl<'a> ReturnExpr<'a> {
     }
 }
 
+// SelfKw
+#[derive(Debug, Clone, Copy,)]
+pub struct SelfKwNode<R: TreeRoot<RaTypes> = OwnedRoot> {
+    pub(crate) syntax: SyntaxNode<R>,
+}
+pub type SelfKw<'a> = SelfKwNode<RefRoot<'a>>;
+
+impl<R1: TreeRoot<RaTypes>, R2: TreeRoot<RaTypes>> PartialEq<SelfKwNode<R1>> for SelfKwNode<R2> {
+    fn eq(&self, other: &SelfKwNode<R1>) -> bool { self.syntax == other.syntax }
+}
+impl<R: TreeRoot<RaTypes>> Eq for SelfKwNode<R> {}
+impl<R: TreeRoot<RaTypes>> Hash for SelfKwNode<R> {
+    fn hash<H: Hasher>(&self, state: &mut H) { self.syntax.hash(state) }
+}
+
+impl<'a> AstNode<'a> for SelfKw<'a> {
+    fn cast(syntax: SyntaxNodeRef<'a>) -> Option<Self> {
+        match syntax.kind() {
+            SELF_KW => Some(SelfKw { syntax }),
+            _ => None,
+        }
+    }
+    fn syntax(self) -> SyntaxNodeRef<'a> { self.syntax }
+}
+
+impl<R: TreeRoot<RaTypes>> SelfKwNode<R> {
+    pub fn borrowed(&self) -> SelfKw {
+        SelfKwNode { syntax: self.syntax.borrowed() }
+    }
+    pub fn owned(&self) -> SelfKwNode {
+        SelfKwNode { syntax: self.syntax.owned() }
+    }
+}
+
+
+impl<'a> SelfKw<'a> {}
+
 // SelfParam
 #[derive(Debug, Clone, Copy,)]
 pub struct SelfParamNode<R: TreeRoot<RaTypes> = OwnedRoot> {
@@ -3487,7 +3560,15 @@ impl<R: TreeRoot<RaTypes>> SelfParamNode<R> {
 }
 
 
-impl<'a> SelfParam<'a> {}
+impl<'a> SelfParam<'a> {
+    pub fn type_ref(self) -> Option<TypeRef<'a>> {
+        super::child_opt(self)
+    }
+
+    pub fn self_kw(self) -> Option<SelfKw<'a>> {
+        super::child_opt(self)
+    }
+}
 
 // SlicePat
 #[derive(Debug, Clone, Copy,)]
diff --git a/crates/ra_syntax/src/grammar.ron b/crates/ra_syntax/src/grammar.ron
index 9a4a96facb..c55e9e07a8 100644
--- a/crates/ra_syntax/src/grammar.ron
+++ b/crates/ra_syntax/src/grammar.ron
@@ -284,6 +284,7 @@ Grammar(
             options: [ "ItemList" ]
         ),
         "ItemList": (
+            collections: [["impl_items", "ImplItem"]],
             traits: [ "FnDefOwner", "ModuleItemOwner" ],
         ),
         "ConstDef": ( traits: [
@@ -307,7 +308,7 @@ Grammar(
             "AttrsOwner",
             "DocCommentsOwner"
         ] ),
-        "ImplBlock": (collections: []),
+        "ImplBlock": (options: ["ItemList"]),
 
         "ParenType": (options: ["TypeRef"]),
         "TupleType": ( collections: [["fields", "TypeRef"]] ),
@@ -351,6 +352,9 @@ Grammar(
             enum: ["StructDef", "EnumDef", "FnDef", "TraitDef", "TypeDef", "ImplBlock",
                    "UseItem", "ExternCrateItem", "ConstDef", "StaticDef", "Module" ]
         ),
+        "ImplItem": (
+            enum: ["FnDef", "TypeDef", "ConstDef"]
+        ),
 
         "TupleExpr": (),
         "ArrayExpr": (),
@@ -530,7 +534,8 @@ Grammar(
                 ["params", "Param"]
             ]
         ),
-        "SelfParam": (),
+        "SelfParam": (options: ["TypeRef", "SelfKw"]),
+        "SelfKw": (),
         "Param": (
             options: [ "Pat", "TypeRef" ],
         ),
diff --git a/crates/ra_syntax/src/grammar/items.rs b/crates/ra_syntax/src/grammar/items.rs
index b9a00b5657..265e84570d 100644
--- a/crates/ra_syntax/src/grammar/items.rs
+++ b/crates/ra_syntax/src/grammar/items.rs
@@ -151,7 +151,7 @@ pub(super) fn maybe_item(p: &mut Parser, flavor: ItemFlavor) -> MaybeItem {
         // test unsafe_default_impl
         // unsafe default impl Foo {}
         IMPL_KW => {
-            traits::impl_item(p);
+            traits::impl_block(p);
             IMPL_BLOCK
         }
         _ => {
diff --git a/crates/ra_syntax/src/grammar/items/traits.rs b/crates/ra_syntax/src/grammar/items/traits.rs
index d4da8b2f72..0a0621753f 100644
--- a/crates/ra_syntax/src/grammar/items/traits.rs
+++ b/crates/ra_syntax/src/grammar/items/traits.rs
@@ -40,9 +40,9 @@ pub(crate) fn trait_item_list(p: &mut Parser) {
     m.complete(p, ITEM_LIST);
 }
 
-// test impl_item
+// test impl_block
 // impl Foo {}
-pub(super) fn impl_item(p: &mut Parser) {
+pub(super) fn impl_block(p: &mut Parser) {
     assert!(p.at(IMPL_KW));
     p.bump();
     if choose_type_params_over_qpath(p) {
@@ -52,7 +52,7 @@ pub(super) fn impl_item(p: &mut Parser) {
     // TODO: never type
     // impl ! {}
 
-    // test impl_item_neg
+    // test impl_block_neg
     // impl !Send for X {}
     p.eat(EXCL);
     impl_type(p);


Test patch:
diff --git a/crates/ra_analysis/tests/test/main.rs b/crates/ra_analysis/tests/test/main.rs
index 859778024a..beeae1e196 100644
--- a/crates/ra_analysis/tests/test/main.rs
+++ b/crates/ra_analysis/tests/test/main.rs
@@ -138,14 +138,14 @@ fn test_resolve_parent_module_for_inline() {
 fn test_resolve_crate_root() {
     let mock = MockAnalysis::with_files(
         "
-        //- /lib.rs
+        //- /bar.rs
         mod foo;
-        //- /foo.rs
+        //- /bar/foo.rs
         // emtpy <|>
     ",
     );
-    let root_file = mock.id_of("/lib.rs");
-    let mod_file = mock.id_of("/foo.rs");
+    let root_file = mock.id_of("/bar.rs");
+    let mod_file = mock.id_of("/bar/foo.rs");
     let mut host = mock.analysis_host();
     assert!(host.analysis().crate_for(mod_file).unwrap().is_empty());
 
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index 93bf431c4d..fb53fcf0be 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -134,6 +134,25 @@ fn test() -> &mut &f64 {
     );
 }
 
+#[test]
+fn infer_self() {
+    check_inference(
+        r#"
+struct S;
+
+impl S {
+    fn test(&self) {
+        self;
+    }
+    fn test2(self: &Self) {
+        self;
+    }
+}
+"#,
+        "0007_self.txt",
+    );
+}
+
 fn infer(content: &str) -> String {
     let (db, _, file_id) = MockDatabase::with_single_file(content);
     let source_file = db.source_file(file_id);
diff --git a/crates/ra_hir/src/ty/tests/data/0007_self.txt b/crates/ra_hir/src/ty/tests/data/0007_self.txt
new file mode 100644
index 0000000000..db4ba17d07
--- /dev/null
+++ b/crates/ra_hir/src/ty/tests/data/0007_self.txt
@@ -0,0 +1,6 @@
+[50; 54) 'self': &S
+[34; 38) 'self': &S
+[40; 61) '{     ...     }': ()
+[88; 109) '{     ...     }': ()
+[98; 102) 'self': &S
+[75; 79) 'self': &S