Repository: rust-analyzer/rust-analyzer
Pull request #693 (2019-01-27 21:07:41)

Name resolution refactoring
This is still very WIP, but it's becoming quite big and I want to make sure this isn't going in a completely bad direction :sweat_smile:. I'm not really happy with how the path resolution looks, and I'm not sure `PerNs<Resolution>` is the best return type -- there are 'this cannot happen in the (types/values) namespace' cases everywhere. I also want to unify the `resolver` and `nameres` namespaces once I'm done switching everything to `Resolver`. Also, `Resolver` only has a lifetime because it needs to have a reference to the `ItemMap` during import resolution :confused: 

The differences in the completion snapshots are almost completely just ordering (except it completes `Self` as well now), so I changed it to sort the completions before snapshotting.

matklad: >The differences in the completion snapshots are almost completely just ordering (except it completes Self as well now), so I changed it to sort the completions before snapshotting.

Let’s file it in a separate pr perhaps to minimize the diff?
matklad: We might also look at:

https://github.com/brendanzab/moniker

I honestly don’t understand what this library is doing exactly, but it seems cool and I am all for using libraries :-)
flodiebold: > Let’s file it in a separate pr perhaps to minimize the diff?

Good point, I already made it a separate commit so I just need to reorder them a bit...
flodiebold: > We might also look at:
> 
> https://github.com/brendanzab/moniker
> 
> I honestly don’t understand what this library is doing exactly, but it seems cool and I am all for using libraries :-)

Yeah, it seems complicated :wink: 
matklad: Terminology note: I use descriptors(kotlin)/symbols(dotty and roslyn)/items(rustc) and defs(rustc) somewhat interchangeably. I suggest using the Def as a general term, as the shortest and least ambiguous. :)
flodiebold: You're right, trying to unify the path resolution like that is the wrong approach. I think wrapping and extending the path resolution of the `ItemMap` will probably work better.
matklad: One important though (which is present in the code, but not documented):

We should only store *scopes* themselves, and avoid storing def-use links: there are many def-use links than scopes, and just resolving use every-time using precomputed scopes should not be that costly. 

Patch:
diff --git a/crates/ra_hir/src/code_model_api.rs b/crates/ra_hir/src/code_model_api.rs
index 71123a6983..92ab0f6922 100644
--- a/crates/ra_hir/src/code_model_api.rs
+++ b/crates/ra_hir/src/code_model_api.rs
@@ -5,18 +5,19 @@ use ra_db::{CrateId, FileId};
 use ra_syntax::{ast::self, TreeArc, SyntaxNode};
 
 use crate::{
-    Name, Path, PerNs, ScopesWithSyntaxMapping, Ty, HirFileId,
+    Name, ScopesWithSyntaxMapping, Ty, HirFileId,
     type_ref::TypeRef,
     nameres::{ModuleScope, lower::ImportId},
     HirDatabase, PersistentHirDatabase,
-    expr::BodySyntaxMapping,
-    ty::{InferenceResult},
+    expr::{Body, BodySyntaxMapping},
+    ty::InferenceResult,
     adt::{EnumVariantId, StructFieldId, VariantDef},
     generics::GenericParams,
     docs::{Documentation, Docs, docs_from_ast},
     module_tree::ModuleId,
     ids::{FunctionId, StructId, EnumId, AstItemDef, ConstId, StaticId, TraitId, TypeId},
     impl_block::ImplId,
+    resolve::Resolver,
 };
 
 /// hir::Crate describes a single crate. It's the main interface with which
@@ -174,13 +175,14 @@ impl Module {
         db.item_map(self.krate)[self.module_id].clone()
     }
 
-    pub fn resolve_path(&self, db: &impl PersistentHirDatabase, path: &Path) -> PerNs<ModuleDef> {
-        db.item_map(self.krate).resolve_path(db, *self, path)
-    }
-
     pub fn problems(&self, db: &impl HirDatabase) -> Vec<(TreeArc<SyntaxNode>, Problem)> {
         self.problems_impl(db)
     }
+
+    pub fn resolver(&self, db: &impl HirDatabase) -> Resolver {
+        let item_map = db.item_map(self.krate);
+        Resolver::default().push_module_scope(item_map, *self)
+    }
 }
 
 impl Docs for Module {
@@ -282,6 +284,21 @@ impl Struct {
     pub fn ty(&self, db: &impl HirDatabase) -> Ty {
         db.type_for_def((*self).into())
     }
+
+    // TODO move to a more general type
+    /// Builds a resolver for type references inside this struct.
+    pub fn resolver(&self, db: &impl HirDatabase) -> Resolver {
+        // take the outer scope...
+        let r = self.module(db).resolver(db);
+        // ...and add generic params, if present
+        let p = self.generic_params(db);
+        let r = if !p.params.is_empty() {
+            r.push_generic_params_scope(p)
+        } else {
+            r
+        };
+        r
+    }
 }
 
 impl Docs for Struct {
@@ -331,6 +348,21 @@ impl Enum {
     pub fn ty(&self, db: &impl HirDatabase) -> Ty {
         db.type_for_def((*self).into())
     }
+
+    // TODO move to a more general type
+    /// Builds a resolver for type references inside this struct.
+    pub fn resolver(&self, db: &impl HirDatabase) -> Resolver {
+        // take the outer scope...
+        let r = self.module(db).resolver(db);
+        // ...and add generic params, if present
+        let p = self.generic_params(db);
+        let r = if !p.params.is_empty() {
+            r.push_generic_params_scope(p)
+        } else {
+            r
+        };
+        r
+    }
 }
 
 impl Docs for Enum {
@@ -449,6 +481,10 @@ impl Function {
         db.body_syntax_mapping(*self)
     }
 
+    pub fn body(&self, db: &impl HirDatabase) -> Arc<Body> {
+        db.body_hir(*self)
+    }
+
     pub fn scopes(&self, db: &impl HirDatabase) -> ScopesWithSyntaxMapping {
         let scopes = db.expr_scopes(*self);
         let syntax_mapping = db.body_syntax_mapping(*self);
@@ -469,6 +505,24 @@ impl Function {
     pub fn generic_params(&self, db: &impl PersistentHirDatabase) -> Arc<GenericParams> {
         db.generic_params((*self).into())
     }
+
+    // TODO move to a more general type for 'body-having' items
+    /// Builds a resolver for code inside this item.
+    pub fn resolver(&self, db: &impl HirDatabase) -> Resolver {
+        // take the outer scope...
+        let r = self
+            .impl_block(db)
+            .map(|ib| ib.resolver(db))
+            .unwrap_or_else(|| self.module(db).resolver(db));
+        // ...and add generic params, if present
+        let p = self.generic_params(db);
+        let r = if !p.params.is_empty() {
+            r.push_generic_params_scope(p)
+        } else {
+            r
+        };
+        r
+    }
 }
 
 impl Docs for Function {
diff --git a/crates/ra_hir/src/code_model_impl/function.rs b/crates/ra_hir/src/code_model_impl/function.rs
index 5b0b31b1d5..8326c02c78 100644
--- a/crates/ra_hir/src/code_model_impl/function.rs
+++ b/crates/ra_hir/src/code_model_impl/function.rs
@@ -5,14 +5,12 @@ use ra_syntax::ast::{self, NameOwner};
 use crate::{
     HirDatabase, Name, AsName, Function, FnSignature,
     type_ref::{TypeRef, Mutability},
-    expr::Body, PersistentHirDatabase,
+    PersistentHirDatabase,
     impl_block::ImplBlock,
 };
 
 impl Function {
-    pub(crate) fn body(&self, db: &impl HirDatabase) -> Arc<Body> {
-        db.body_hir(*self)
-    }
+    // TODO impl_block should probably also be part of the code model API?
 
     /// The containing impl block, if this is a method.
     pub(crate) fn impl_block(&self, db: &impl HirDatabase) -> Option<ImplBlock> {
diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs
index f4a9504184..f9f702ae2b 100644
--- a/crates/ra_hir/src/expr.rs
+++ b/crates/ra_hir/src/expr.rs
@@ -10,15 +10,15 @@ use ra_syntax::{
 };
 
 use crate::{
-    Path, Name, Function,
-    name::AsName, HirDatabase,
+    Path, Name, HirDatabase, Function, Resolver,
+    name::AsName,
     type_ref::{Mutability, TypeRef},
 };
 use crate::ty::primitive::{UintTy, UncertainIntTy, UncertainFloatTy};
 
 pub use self::scope::{ExprScopes, ScopesWithSyntaxMapping, ScopeEntryWithSyntax};
 
-mod scope;
+pub(crate) mod scope;
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
 pub struct ExprId(RawId);
@@ -27,6 +27,9 @@ impl_arena_id!(ExprId);
 /// The body of an item (function, const etc.).
 #[derive(Debug, Eq, PartialEq)]
 pub struct Body {
+    // TODO: this should be more general, consts & statics also have bodies
+    /// The Function of the item this body belongs to
+    owner: Function,
     exprs: Arena<ExprId, Expr>,
     pats: Arena<PatId, Pat>,
     /// The patterns for the function's parameters. While the parameter types are
@@ -62,6 +65,34 @@ impl Body {
     pub fn body_expr(&self) -> ExprId {
         self.body_expr
     }
+
+    pub fn owner(&self) -> Function {
+        self.owner
+    }
+
+    pub fn syntax_mapping(&self, db: &impl HirDatabase) -> Arc<BodySyntaxMapping> {
+        db.body_syntax_mapping(self.owner)
+    }
+}
+
+// needs arbitrary_self_types to be a method... or maybe move to the def?
+pub fn resolver_for_expr(body: Arc<Body>, db: &impl HirDatabase, expr_id: ExprId) -> Resolver {
+    let scopes = db.expr_scopes(body.owner);
+    resolver_for_scope(body, db, scopes.scope_for(expr_id))
+}
+
+pub fn resolver_for_scope(
+    body: Arc<Body>,
+    db: &impl HirDatabase,
+    scope_id: Option<scope::ScopeId>,
+) -> Resolver {
+    let mut r = body.owner.resolver(db);
+    let scopes = db.expr_scopes(body.owner);
+    let scope_chain = scopes.scope_chain_for(scope_id).collect::<Vec<_>>();
+    for scope in scope_chain.into_iter().rev() {
+        r = r.push_expr_scope(Arc::clone(&scopes), scope);
+    }
+    r
 }
 
 impl Index<ExprId> for Body {
@@ -448,23 +479,29 @@ pub(crate) fn body_hir(db: &impl HirDatabase, func: Function) -> Arc<Body> {
 }
 
 struct ExprCollector {
+    owner: Function,
     exprs: Arena<ExprId, Expr>,
     pats: Arena<PatId, Pat>,
     expr_syntax_mapping: FxHashMap<SyntaxNodePtr, ExprId>,
     expr_syntax_mapping_back: ArenaMap<ExprId, SyntaxNodePtr>,
     pat_syntax_mapping: FxHashMap<SyntaxNodePtr, PatId>,
     pat_syntax_mapping_back: ArenaMap<PatId, SyntaxNodePtr>,
+    params: Vec<PatId>,
+    body_expr: Option<ExprId>,
 }
 
 impl ExprCollector {
-    fn new() -> Self {
+    fn new(owner: Function) -> Self {
         ExprCollector {
+            owner,
             exprs: Arena::default(),
             pats: Arena::default(),
             expr_syntax_mapping: FxHashMap::default(),
             expr_syntax_mapping_back: ArenaMap::default(),
             pat_syntax_mapping: FxHashMap::default(),
             pat_syntax_mapping_back: ArenaMap::default(),
+            params: Vec::new(),
+            body_expr: None,
         }
     }
 
@@ -902,10 +939,7 @@ impl ExprCollector {
                 });
                 fields.extend(iter);
 
-                Pat::Struct {
-                    path: path,
-                    args: fields,
-                }
+                Pat::Struct { path, args: fields }
             }
 
             // TODO: implement
@@ -923,12 +957,48 @@ impl ExprCollector {
         }
     }
 
-    fn into_body_syntax_mapping(self, params: Vec<PatId>, body_expr: ExprId) -> BodySyntaxMapping {
+    fn collect_fn_body(&mut self, node: &ast::FnDef) {
+        if let Some(param_list) = node.param_list() {
+            if let Some(self_param) = param_list.self_param() {
+                let self_param = SyntaxNodePtr::new(
+                    self_param
+                        .self_kw()
+                        .expect("self param without self keyword")
+                        .syntax(),
+                );
+                let param_pat = self.alloc_pat(
+                    Pat::Bind {
+                        name: Name::self_param(),
+                        mode: BindingAnnotation::Unannotated,
+                        subpat: None,
+                    },
+                    self_param,
+                );
+                self.params.push(param_pat);
+            }
+
+            for param in param_list.params() {
+                let pat = if let Some(pat) = param.pat() {
+                    pat
+                } else {
+                    continue;
+                };
+                let param_pat = self.collect_pat(pat);
+                self.params.push(param_pat);
+            }
+        };
+
+        let body = self.collect_block_opt(node.body());
+        self.body_expr = Some(body);
+    }
+
+    fn into_body_syntax_mapping(self) -> BodySyntaxMapping {
         let body = Body {
+            owner: self.owner,
             exprs: self.exprs,
             pats: self.pats,
-            params,
-            body_expr,
+            params: self.params,
+            body_expr: self.body_expr.expect("A body should have been collected"),
         };
         BodySyntaxMapping {
             body: Arc::new(body),
@@ -940,49 +1010,18 @@ impl ExprCollector {
     }
 }
 
-pub(crate) fn collect_fn_body_syntax(node: &ast::FnDef) -> BodySyntaxMapping {
-    let mut collector = ExprCollector::new();
-
-    let params = if let Some(param_list) = node.param_list() {
-        let mut params = Vec::new();
-
-        if let Some(self_param) = param_list.self_param() {
-            let self_param = SyntaxNodePtr::new(
-                self_param
-                    .self_kw()
-                    .expect("self param without self keyword")
-                    .syntax(),
-            );
-            let param = collector.alloc_pat(
-                Pat::Bind {
-                    name: Name::self_param(),
-                    mode: BindingAnnotation::Unannotated,
-                    subpat: None,
-                },
-                self_param,
-            );
-            params.push(param);
-        }
+pub(crate) fn body_syntax_mapping(db: &impl HirDatabase, func: Function) -> Arc<BodySyntaxMapping> {
+    let mut collector = ExprCollector::new(func);
 
-        for param in param_list.params() {
-            let pat = if let Some(pat) = param.pat() {
-                pat
-            } else {
-                continue;
-            };
-            params.push(collector.collect_pat(pat));
-        }
-        params
-    } else {
-        Vec::new()
-    };
+    // TODO: consts, etc.
+    collector.collect_fn_body(&func.source(db).1);
 
-    let body = collector.collect_block_opt(node.body());
-    collector.into_body_syntax_mapping(params, body)
+    Arc::new(collector.into_body_syntax_mapping())
 }
 
-pub(crate) fn body_syntax_mapping(db: &impl HirDatabase, func: Function) -> Arc<BodySyntaxMapping> {
-    let (_, fn_def) = func.source(db);
-    let body_syntax_mapping = collect_fn_body_syntax(&fn_def);
-    Arc::new(body_syntax_mapping)
+#[cfg(test)]
+pub(crate) fn collect_fn_body_syntax(function: Function, node: &ast::FnDef) -> BodySyntaxMapping {
+    let mut collector = ExprCollector::new(function);
+    collector.collect_fn_body(node);
+    collector.into_body_syntax_mapping()
 }
diff --git a/crates/ra_hir/src/expr/scope.rs b/crates/ra_hir/src/expr/scope.rs
index b7971088d0..9202e36712 100644
--- a/crates/ra_hir/src/expr/scope.rs
+++ b/crates/ra_hir/src/expr/scope.rs
@@ -58,28 +58,19 @@ impl ExprScopes {
         scopes
     }
 
-    pub fn entries(&self, scope: ScopeId) -> &[ScopeEntry] {
-        &self.scopes[scope].entries
+    pub fn body(&self) -> Arc<Body> {
+        self.body.clone()
     }
 
-    pub fn scope_chain_for<'a>(&'a self, expr: ExprId) -> impl Iterator<Item = ScopeId> + 'a {
-        generate(self.scope_for(expr), move |&scope| {
-            self.scopes[scope].parent
-        })
+    pub fn entries(&self, scope: ScopeId) -> &[ScopeEntry] {
+        &self.scopes[scope].entries
     }
 
-    pub fn resolve_local_name<'a>(
+    pub fn scope_chain_for<'a>(
         &'a self,
-        context_expr: ExprId,
-        name: Name,
-    ) -> Option<&'a ScopeEntry> {
-        let mut shadowed = FxHashSet::default();
-        let ret = self
-            .scope_chain_for(context_expr)
-            .flat_map(|scope| self.entries(scope).iter())
-            .filter(|entry| shadowed.insert(entry.name()))
-            .find(|entry| entry.name() == &name);
-        ret
+        scope: Option<ScopeId>,
+    ) -> impl Iterator<Item = ScopeId> + 'a {
+        generate(scope, move |&scope| self.scopes[scope].parent)
     }
 
     fn root_scope(&mut self) -> ScopeId {
@@ -122,7 +113,7 @@ impl ExprScopes {
         self.scope_for.insert(node, scope);
     }
 
-    fn scope_for(&self, expr: ExprId) -> Option<ScopeId> {
+    pub fn scope_for(&self, expr: ExprId) -> Option<ScopeId> {
         self.scope_for.get(&expr).map(|&scope| scope)
     }
 }
@@ -150,18 +141,14 @@ impl ScopeEntryWithSyntax {
 }
 
 impl ScopesWithSyntaxMapping {
-    pub fn scope_chain<'a>(&'a self, node: &SyntaxNode) -> impl Iterator<Item = ScopeId> + 'a {
+    fn scope_chain<'a>(&'a self, node: &SyntaxNode) -> impl Iterator<Item = ScopeId> + 'a {
         generate(self.scope_for(node), move |&scope| {
             self.scopes.scopes[scope].parent
         })
     }
 
-    pub fn scope_chain_for_offset<'a>(
-        &'a self,
-        offset: TextUnit,
-    ) -> impl Iterator<Item = ScopeId> + 'a {
-        let scope = self
-            .scopes
+    pub fn scope_for_offset<'a>(&'a self, offset: TextUnit) -> Option<ScopeId> {
+        self.scopes
             .scope_for
             .iter()
             .filter_map(|(id, scope)| Some((self.syntax_mapping.expr_syntax(*id)?, scope)))
@@ -172,13 +159,12 @@ impl ScopesWithSyntaxMapping {
                     ptr.range().len(),
                 )
             })
-            .map(|(ptr, scope)| self.adjust(ptr, *scope, offset));
-
-        generate(scope, move |&scope| self.scopes.scopes[scope].parent)
+            .map(|(ptr, scope)| self.adjust(ptr, *scope, offset))
     }
 
     // XXX: during completion, cursor might be outside of any particular
     // expression. Try to figure out the correct scope...
+    // TODO: move this to source binder?
     fn adjust(&self, ptr: SyntaxNodePtr, original_scope: ScopeId, offset: TextUnit) -> ScopeId {
         let r = ptr.range();
         let child_scopes = self
@@ -238,7 +224,7 @@ impl ScopesWithSyntaxMapping {
             .collect()
     }
 
-    fn scope_for(&self, node: &SyntaxNode) -> Option<ScopeId> {
+    pub fn scope_for(&self, node: &SyntaxNode) -> Option<ScopeId> {
         node.ancestors()
             .map(SyntaxNodePtr::new)
             .filter_map(|ptr| self.syntax_mapping.syntax_expr(ptr))
@@ -336,6 +322,7 @@ pub struct ReferenceDescriptor {
 mod tests {
     use ra_syntax::{SourceFile, algo::find_node_at_offset};
     use test_utils::{extract_offset, assert_eq_text};
+    use ra_arena::ArenaId;
 
     use crate::expr;
 
@@ -354,7 +341,10 @@ mod tests {
         let file = SourceFile::parse(&code);
         let marker: &ast::PathExpr = find_node_at_offset(file.syntax(), off).unwrap();
         let fn_def: &ast::FnDef = find_node_at_offset(file.syntax(), off).unwrap();
-        let body_hir = expr::collect_fn_body_syntax(fn_def);
+        let irrelevant_function = Function {
+            id: crate::ids::FunctionId::from_raw(0.into()),
+        };
+        let body_hir = expr::collect_fn_body_syntax(irrelevant_function, fn_def);
         let scopes = ExprScopes::new(Arc::clone(body_hir.body()));
         let scopes = ScopesWithSyntaxMapping {
             scopes: Arc::new(scopes),
@@ -454,7 +444,10 @@ mod tests {
         let fn_def: &ast::FnDef = find_node_at_offset(file.syntax(), off).unwrap();
         let name_ref: &ast::NameRef = find_node_at_offset(file.syntax(), off).unwrap();
 
-        let body_hir = expr::collect_fn_body_syntax(fn_def);
+        let irrelevant_function = Function {
+            id: crate::ids::FunctionId::from_raw(0.into()),
+        };
+        let body_hir = expr::collect_fn_body_syntax(irrelevant_function, fn_def);
         let scopes = ExprScopes::new(Arc::clone(body_hir.body()));
         let scopes = ScopesWithSyntaxMapping {
             scopes: Arc::new(scopes),
diff --git a/crates/ra_hir/src/generics.rs b/crates/ra_hir/src/generics.rs
index b0bd735bda..a82205f0b3 100644
--- a/crates/ra_hir/src/generics.rs
+++ b/crates/ra_hir/src/generics.rs
@@ -12,6 +12,7 @@ use crate::{db::PersistentHirDatabase, Name, AsName, Function, Struct, Enum, Tra
 /// Data about a generic parameter (to a function, struct, impl, ...).
 #[derive(Clone, PartialEq, Eq, Debug)]
 pub struct GenericParam {
+    // TODO: give generic params proper IDs
     pub(crate) idx: u32,
     pub(crate) name: Name,
 }
diff --git a/crates/ra_hir/src/impl_block.rs b/crates/ra_hir/src/impl_block.rs
index 36d72b103b..738c58fbe8 100644
--- a/crates/ra_hir/src/impl_block.rs
+++ b/crates/ra_hir/src/impl_block.rs
@@ -7,11 +7,13 @@ use ra_syntax::{
 ast::{self, AstNode}};
 
 use crate::{
-    Const, Type,
-    Function, HirFileId,
-    PersistentHirDatabase,
+    Const, Type, Function, HirFileId,
+    HirDatabase, PersistentHirDatabase,
+    ModuleDef, Trait, Resolution,
     type_ref::TypeRef,
     ids::LocationCtx,
+    resolve::Resolver,
+    ty::Ty,
 };
 
 use crate::code_model_api::{Module, ModuleSource};
@@ -69,7 +71,11 @@ impl ImplBlock {
         &self.module_impl_blocks.impls[self.impl_id]
     }
 
-    pub fn target_trait(&self) -> Option<&TypeRef> {
+    pub fn module(&self) -> Module {
+        self.module_impl_blocks.module.clone()
+    }
+
+    pub fn target_trait_ref(&self) -> Option<&TypeRef> {
         self.impl_data().target_trait()
     }
 
@@ -77,9 +83,32 @@ impl ImplBlock {
         self.impl_data().target_type()
     }
 
+    pub fn target_ty(&self, db: &impl HirDatabase) -> Ty {
+        Ty::from_hir(db, &self.resolver(db), self.target_type())
+    }
+
+    pub fn target_trait(&self, db: &impl HirDatabase) -> Option<Trait> {
+        if let Some(TypeRef::Path(path)) = self.target_trait_ref() {
+            let resolver = self.resolver(db);
+            if let Some(Resolution::Def(ModuleDef::Trait(tr))) =
+                resolver.resolve_path(db, path).take_types()
+            {
+                return Some(tr);
+            }
+        }
+        None
+    }
+
     pub fn items(&self) -> &[ImplItem] {
         self.impl_data().items()
     }
+
+    pub fn resolver(&self, db: &impl HirDatabase) -> Resolver {
+        let r = self.module().resolver(db);
+        // TODO: add generics
+        let r = r.push_impl_block_scope(self.clone());
+        r
+    }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq)]
@@ -162,25 +191,24 @@ impl_arena_id!(ImplId);
 /// we don't need to do the second step again.
 #[derive(Debug, PartialEq, Eq)]
 pub struct ModuleImplBlocks {
+    module: Module,
     pub(crate) impls: Arena<ImplId, ImplData>,
     impls_by_def: FxHashMap<ImplItem, ImplId>,
 }
 
 impl ModuleImplBlocks {
-    fn new() -> Self {
-        ModuleImplBlocks {
-            impls: Arena::default(),
-            impls_by_def: FxHashMap::default(),
-        }
-    }
-
     fn collect(
-        &mut self,
         db: &impl PersistentHirDatabase,
         module: Module,
         source_map: &mut ImplSourceMap,
-    ) {
-        let (file_id, module_source) = module.definition_source(db);
+    ) -> Self {
+        let mut m = ModuleImplBlocks {
+            module,
+            impls: Arena::default(),
+            impls_by_def: FxHashMap::default(),
+        };
+
+        let (file_id, module_source) = m.module.definition_source(db);
         let file_id: HirFileId = file_id.into();
         let node = match &module_source {
             ModuleSource::SourceFile(node) => node.syntax(),
@@ -191,14 +219,16 @@ impl ModuleImplBlocks {
         };
 
         for impl_block_ast in node.children().filter_map(ast::ImplBlock::cast) {
-            let impl_block = ImplData::from_ast(db, file_id, 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, id);
+            let impl_block = ImplData::from_ast(db, file_id, m.module, impl_block_ast);
+            let id = m.impls.alloc(impl_block);
+            for &impl_item in &m.impls[id].items {
+                m.impls_by_def.insert(impl_item, id);
             }
 
             source_map.insert(id, impl_block_ast);
         }
+
+        m
     }
 }
 
@@ -208,8 +238,7 @@ pub(crate) fn impls_in_module_with_source_map_query(
 ) -> (Arc<ModuleImplBlocks>, Arc<ImplSourceMap>) {
     let mut source_map = ImplSourceMap::default();
 
-    let mut result = ModuleImplBlocks::new();
-    result.collect(db, module, &mut source_map);
+    let result = ModuleImplBlocks::collect(db, module, &mut source_map);
 
     (Arc::new(result), Arc::new(source_map))
 }
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs
index 905c53c7dd..54da555985 100644
--- a/crates/ra_hir/src/lib.rs
+++ b/crates/ra_hir/src/lib.rs
@@ -36,6 +36,7 @@ mod impl_block;
 mod expr;
 mod generics;
 mod docs;
+mod resolve;
 
 mod code_model_api;
 mod code_model_impl;
@@ -54,12 +55,13 @@ pub use self::{
     name::Name,
     ids::{HirFileId, MacroCallId, MacroCallLoc, HirInterner},
     macros::{MacroDef, MacroInput, MacroExpansion},
-    nameres::{ItemMap, PerNs, Namespace, Resolution},
+    nameres::{ItemMap, PerNs, Namespace},
     ty::Ty,
     impl_block::{ImplBlock, ImplItem},
     docs::{Docs, Documentation},
     adt::AdtDef,
     expr::{ExprScopes, ScopesWithSyntaxMapping},
+    resolve::{Resolver, Resolution},
 };
 
 pub use self::code_model_api::{
diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs
index f8627acbe0..7ec6512b64 100644
--- a/crates/ra_hir/src/nameres.rs
+++ b/crates/ra_hir/src/nameres.rs
@@ -24,13 +24,13 @@ use rustc_hash::{FxHashMap, FxHashSet};
 
 use crate::{
     Module, ModuleDef,
-    Path, PathKind, Crate,
-    Name, PersistentHirDatabase,
+    Path, PathKind, PersistentHirDatabase,
+    Crate, Name,
     module_tree::{ModuleId, ModuleTree},
     nameres::lower::{ImportId, LoweredModule, ImportData},
 };
 
-/// `ItemMap` is the result of name resolution. It contains, for each
+/// `ItemMap` is the result of module name resolution. It contains, for each
 /// module, the set of visible items.
 #[derive(Default, Debug, PartialEq, Eq)]
 pub struct ItemMap {
@@ -46,7 +46,7 @@ impl std::ops::Index<ModuleId> for ItemMap {
 
 #[derive(Debug, Default, PartialEq, Eq, Clone)]
 pub struct ModuleScope {
-    items: FxHashMap<Name, Resolution>,
+    pub(crate) items: FxHashMap<Name, Resolution>,
 }
 
 impl ModuleScope {
@@ -80,6 +80,15 @@ pub struct PerNs<T> {
     pub values: Option<T>,
 }
 
+impl<T> Default for PerNs<T> {
+    fn default() -> Self {
+        PerNs {
+            types: None,
+            values: None,
+        }
+    }
+}
+
 impl<T> PerNs<T> {
     pub fn none() -> PerNs<T> {
         PerNs {
@@ -113,6 +122,10 @@ impl<T> PerNs<T> {
         self.types.is_none() && self.values.is_none()
     }
 
+    pub fn is_both(&self) -> bool {
+        self.types.is_some() && self.values.is_some()
+    }
+
     pub fn take(self, namespace: Namespace) -> Option<T> {
         match namespace {
             Namespace::Types => self.types,
@@ -139,6 +152,13 @@ impl<T> PerNs<T> {
         }
     }
 
+    pub fn combine(self, other: PerNs<T>) -> PerNs<T> {
+        PerNs {
+            types: self.types.or(other.types),
+            values: self.values.or(other.values),
+        }
+    }
+
     pub fn and_then<U>(self, f: impl Fn(T) -> Option<U>) -> PerNs<U> {
         PerNs {
             types: self.types.and_then(&f),
@@ -402,10 +422,11 @@ impl ItemMap {
                     if module.krate != original_module.krate {
                         let path = Path {
                             segments: path.segments[i..].iter().cloned().collect(),
-                            kind: PathKind::Crate,
+                            kind: PathKind::Self_,
                         };
                         log::debug!("resolving {:?} in other crate", path);
-                        let def = module.resolve_path(db, &path);
+                        let item_map = db.item_map(module.krate);
+                        let def = item_map.resolve_path(db, *module, &path);
                         return (def, ReachedFixedPoint::Yes);
                     }
 
diff --git a/crates/ra_hir/src/resolve.rs b/crates/ra_hir/src/resolve.rs
new file mode 100644
index 0000000000..6c87d0df72
--- /dev/null
+++ b/crates/ra_hir/src/resolve.rs
@@ -0,0 +1,226 @@
+//! Name resolution.
+use std::sync::Arc;
+
+use rustc_hash::FxHashMap;
+
+use crate::{
+    ModuleDef, Module,
+    db::HirDatabase,
+    name::{Name, KnownName},
+    nameres::{PerNs, ItemMap},
+    generics::GenericParams,
+    expr::{scope::{ExprScopes, ScopeId}, PatId, Body},
+    impl_block::ImplBlock,
+    path::Path,
+};
+
+#[derive(Debug, Clone, Default)]
+pub struct Resolver {
+    scopes: Vec<Scope>,
+}
+
+// TODO how to store these best
+#[derive(Debug, Clone)]
+pub(crate) struct ModuleItemMap {
+    item_map: Arc<ItemMap>,
+    module: Module,
+}
+
+#[derive(Debug, Clone)]
+pub(crate) struct ExprScope {
+    expr_scopes: Arc<ExprScopes>,
+    scope_id: ScopeId,
+}
+
+#[derive(Debug, Clone)]
+pub(crate) enum Scope {
+    /// All the items and imported names of a module
+    ModuleScope(ModuleItemMap),
+    /// Brings the generic parameters of an item into scope
+    GenericParams(Arc<GenericParams>),
+    /// Brings `Self` into scope
+    ImplBlockScope(ImplBlock),
+    /// Local bindings
+    ExprScope(ExprScope),
+}
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub enum Resolution {
+    /// An item
+    Def(ModuleDef),
+    /// A local binding (only value namespace)
+    LocalBinding(PatId),
+    /// A generic parameter
+    GenericParam(u32),
+    SelfType(ImplBlock),
+}
+
+impl Resolver {
+    pub fn resolve_name(&self, name: &Name) -> PerNs<Resolution> {
+        let mut resolution = PerNs::none();
+        for scope in self.scopes.iter().rev() {
+            resolution = resolution.combine(scope.resolve_name(name));
+            if resolution.is_both() {
+                return resolution;
+            }
+        }
+        resolution
+    }
+
+    pub fn resolve_path(&self, db: &impl HirDatabase, path: &Path) -> PerNs<Resolution> {
+        if let Some(name) = path.as_ident() {
+            self.resolve_name(name)
+        } else if path.is_self() {
+            self.resolve_name(&Name::self_param())
+        } else {
+            let (item_map, module) = match self.module() {
+                Some(m) => m,
+                _ => return PerNs::none(),
+            };
+            let module_res = item_map.resolve_path(db, module, path);
+            module_res.map(|def| Resolution::Def(def))
+        }
+    }
+
+    pub fn all_names(&self) -> FxHashMap<Name, PerNs<Resolution>> {
+        let mut names = FxHashMap::default();
+        for scope in self.scopes.iter().rev() {
+            scope.collect_names(&mut |name, res| {
+                let current: &mut PerNs<Resolution> = names.entry(name).or_default();
+                if current.types.is_none() {
+                    current.types = res.types;
+                }
+                if current.values.is_none() {
+                    current.values = res.values;
+                }
+            });
+        }
+        names
+    }
+
+    fn module(&self) -> Option<(&ItemMap, Module)> {
+        self.scopes.iter().rev().find_map(|scope| match scope {
+            Scope::ModuleScope(m) => Some((&*m.item_map, m.module.clone())),
+
+            _ => None,
+        })
+    }
+
+    /// The body from which any `LocalBinding` resolutions in this resolver come.
+    pub fn body(&self) -> Option<Arc<Body>> {
+        self.scopes.iter().rev().find_map(|scope| match scope {
+            Scope::ExprScope(expr_scope) => Some(expr_scope.expr_scopes.body()),
+            _ => None,
+        })
+    }
+}
+
+impl Resolver {
+    pub(crate) fn push_scope(mut self, scope: Scope) -> Resolver {
+        self.scopes.push(scope);
+        self
+    }
+
+    pub(crate) fn push_generic_params_scope(self, params: Arc<GenericParams>) -> Resolver {
+        self.push_scope(Scope::GenericParams(params))
+    }
+
+    pub(crate) fn push_impl_block_scope(self, impl_block: ImplBlock) -> Resolver {
+        self.push_scope(Scope::ImplBlockScope(impl_block))
+    }
+
+    pub(crate) fn push_module_scope(self, item_map: Arc<ItemMap>, module: Module) -> Resolver {
+        self.push_scope(Scope::ModuleScope(ModuleItemMap { item_map, module }))
+    }
+
+    pub(crate) fn push_expr_scope(
+        self,
+        expr_scopes: Arc<ExprScopes>,
+        scope_id: ScopeId,
+    ) -> Resolver {
+        self.push_scope(Scope::ExprScope(ExprScope {
+            expr_scopes,
+            scope_id,
+        }))
+    }
+}
+
+impl Scope {
+    fn resolve_name(&self, name: &Name) -> PerNs<Resolution> {
+        match self {
+            Scope::ModuleScope(m) => {
+                if let Some(KnownName::SelfParam) = name.as_known_name() {
+                    PerNs::types(Resolution::Def(m.module.into()))
+                } else {
+                    match m.item_map[m.module.module_id].get(name) {
+                        Some(res) => res.def.map(Resolution::Def),
+                        None => PerNs::none(),
+                    }
+                }
+            }
+            Scope::GenericParams(gp) => match gp.find_by_name(name) {
+                Some(gp) => PerNs::types(Resolution::GenericParam(gp.idx)),
+                None => PerNs::none(),
+            },
+            Scope::ImplBlockScope(i) => {
+                if name.as_known_name() == Some(KnownName::SelfType) {
+                    PerNs::types(Resolution::SelfType(i.clone()))
+                } else {
+                    PerNs::none()
+                }
+            }
+            Scope::ExprScope(e) => {
+                let entry = e
+                    .expr_scopes
+                    .entries(e.scope_id)
+                    .iter()
+                    .find(|entry| entry.name() == name);
+                match entry {
+                    Some(e) => PerNs::values(Resolution::LocalBinding(e.pat())),
+                    None => PerNs::none(),
+                }
+            }
+        }
+    }
+
+    fn collect_names(&self, f: &mut FnMut(Name, PerNs<Resolution>)) {
+        match self {
+            Scope::ModuleScope(m) => {
+                // TODO: should we provide `self` here?
+                // f(
+                //     Name::self_param(),
+                //     PerNs::types(Resolution::Def {
+                //         def: m.module.into(),
+                //     }),
+                // );
+                m.item_map[m.module.module_id]
+                    .entries()
+                    .for_each(|(name, res)| {
+                        f(name.clone(), res.def.map(Resolution::Def));
+                    })
+            }
+            Scope::GenericParams(gp) => {
+                for param in &gp.params {
+                    f(
+                        param.name.clone(),
+                        PerNs::types(Resolution::GenericParam(param.idx)),
+                    )
+                }
+            }
+            Scope::ImplBlockScope(i) => {
+                f(
+                    Name::self_type(),
+                    PerNs::types(Resolution::SelfType(i.clone())),
+                );
+            }
+            Scope::ExprScope(e) => {
+                e.expr_scopes.entries(e.scope_id).iter().for_each(|e| {
+                    f(
+                        e.name().clone(),
+                        PerNs::values(Resolution::LocalBinding(e.pat())),
+                    );
+                });
+            }
+        }
+    }
+}
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs
index a1b94ed9c9..59f7822774 100644
--- a/crates/ra_hir/src/source_binder.rs
+++ b/crates/ra_hir/src/source_binder.rs
@@ -9,13 +9,14 @@ use ra_db::{FileId, FilePosition};
 use ra_syntax::{
     SmolStr, TextRange, SyntaxNode,
     ast::{self, AstNode, NameOwner},
-    algo::find_node_at_offset,
+    algo::{find_node_at_offset, find_leaf_at_offset},
 };
 
 use crate::{
     HirDatabase, Function, ModuleDef, Struct, Enum,
-    AsName, Module, HirFileId, Crate, Trait,
+    AsName, Module, HirFileId, Crate, Trait, Resolver,
     ids::{LocationCtx, SourceFileItemId},
+    expr
 };
 
 /// Locates the module by `FileId`. Picks topmost module in the file.
@@ -201,3 +202,67 @@ pub fn macro_symbols(db: &impl HirDatabase, file_id: FileId) -> Vec<(SmolStr, Te
 
     res
 }
+
+pub fn resolver_for_position(db: &impl HirDatabase, position: FilePosition) -> Resolver {
+    let file_id = position.file_id;
+    let file = db.parse(file_id);
+    find_leaf_at_offset(file.syntax(), position.offset)
+        .find_map(|node| {
+            node.ancestors().find_map(|node| {
+                if ast::Expr::cast(node).is_some() || ast::Block::cast(node).is_some() {
+                    if let Some(func) = function_from_child_node(db, file_id, node) {
+                        let scopes = func.scopes(db);
+                        let scope = scopes.scope_for_offset(position.offset);
+                        Some(expr::resolver_for_scope(func.body(db), db, scope))
+                    } else {
+                        // TODO const/static/array length
+                        None
+                    }
+                } else if let Some(module) = ast::Module::cast(node) {
+                    Some(module_from_declaration(db, file_id, module)?.resolver(db))
+                } else if let Some(_) = ast::SourceFile::cast(node) {
+                    Some(module_from_source(db, file_id.into(), None)?.resolver(db))
+                } else if let Some(s) = ast::StructDef::cast(node) {
+                    let module = module_from_child_node(db, file_id, s.syntax())?;
+                    Some(struct_from_module(db, module, s).resolver(db))
+                } else if let Some(e) = ast::EnumDef::cast(node) {
+                    let module = module_from_child_node(db, file_id, e.syntax())?;
+                    Some(enum_from_module(db, module, e).resolver(db))
+                } else {
+                    // TODO add missing cases
+                    None
+                }
+            })
+        })
+        .unwrap_or_default()
+}
+
+pub fn resolver_for_node(db: &impl HirDatabase, file_id: FileId, node: &SyntaxNode) -> Resolver {
+    node.ancestors()
+        .find_map(|node| {
+            if ast::Expr::cast(node).is_some() || ast::Block::cast(node).is_some() {
+                if let Some(func) = function_from_child_node(db, file_id, node) {
+                    let scopes = func.scopes(db);
+                    let scope = scopes.scope_for(&node);
+                    Some(expr::resolver_for_scope(func.body(db), db, scope))
+                } else {
+                    // TODO const/static/array length
+                    None
+                }
+            } else if let Some(module) = ast::Module::cast(node) {
+                Some(module_from_declaration(db, file_id, module)?.resolver(db))
+            } else if let Some(_) = ast::SourceFile::cast(node) {
+                Some(module_from_source(db, file_id.into(), None)?.resolver(db))
+            } else if let Some(s) = ast::StructDef::cast(node) {
+                let module = module_from_child_node(db, file_id, s.syntax())?;
+                Some(struct_from_module(db, module, s).resolver(db))
+            } else if let Some(e) = ast::EnumDef::cast(node) {
+                let module = module_from_child_node(db, file_id, e.syntax())?;
+                Some(enum_from_module(db, module, e).resolver(db))
+            } else {
+                // TODO add missing cases
+                None
+            }
+        })
+        .unwrap_or_default()
+}
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs
index d3e31981a8..cc5afad753 100644
--- a/crates/ra_hir/src/ty.rs
+++ b/crates/ra_hir/src/ty.rs
@@ -33,15 +33,16 @@ use rustc_hash::FxHashMap;
 use test_utils::tested_by;
 
 use crate::{
-    Module, Function, Struct, StructField, Enum, EnumVariant, Path, Name, ImplBlock,
-    FnSignature, ExprScopes, ModuleDef, AdtDef,
+    Function, Struct, StructField, Enum, EnumVariant, Path, Name,
+    FnSignature, ModuleDef, AdtDef,
     HirDatabase,
     type_ref::{TypeRef, Mutability},
     name::KnownName,
-    expr::{Body, Expr, BindingAnnotation, Literal, ExprId, Pat, PatId, UnaryOp, BinaryOp, Statement, FieldPat},
+    expr::{Body, Expr, BindingAnnotation, Literal, ExprId, Pat, PatId, UnaryOp, BinaryOp, Statement, FieldPat, self},
     generics::GenericParams,
     path::GenericArg,
     adt::VariantDef,
+    resolve::{Resolver, Resolution},
 };
 
 /// The ID of a type variable.
@@ -300,47 +301,38 @@ pub struct FnSig {
 }
 
 impl Ty {
-    pub(crate) fn from_hir(
-        db: &impl HirDatabase,
-        // TODO: the next three parameters basically describe the scope for name
-        // resolution; this should be refactored into something like a general
-        // resolver architecture
-        module: &Module,
-        impl_block: Option<&ImplBlock>,
-        generics: &GenericParams,
-        type_ref: &TypeRef,
-    ) -> Self {
+    pub(crate) fn from_hir(db: &impl HirDatabase, resolver: &Resolver, type_ref: &TypeRef) -> Self {
         match type_ref {
             TypeRef::Never => Ty::Never,
             TypeRef::Tuple(inner) => {
                 let inner_tys = inner
                     .iter()
-                    .map(|tr| Ty::from_hir(db, module, impl_block, generics, tr))
+                    .map(|tr| Ty::from_hir(db, resolver, tr))
                     .collect::<Vec<_>>();
                 Ty::Tuple(inner_tys.into())
             }
-            TypeRef::Path(path) => Ty::from_hir_path(db, module, impl_block, generics, path),
+            TypeRef::Path(path) => Ty::from_hir_path(db, resolver, path),
             TypeRef::RawPtr(inner, mutability) => {
-                let inner_ty = Ty::from_hir(db, module, impl_block, generics, inner);
+                let inner_ty = Ty::from_hir(db, resolver, inner);
                 Ty::RawPtr(Arc::new(inner_ty), *mutability)
             }
             TypeRef::Array(inner) => {
-                let inner_ty = Ty::from_hir(db, module, impl_block, generics, inner);
+                let inner_ty = Ty::from_hir(db, resolver, inner);
                 Ty::Array(Arc::new(inner_ty))
             }
             TypeRef::Slice(inner) => {
-                let inner_ty = Ty::from_hir(db, module, impl_block, generics, inner);
+                let inner_ty = Ty::from_hir(db, resolver, inner);
                 Ty::Slice(Arc::new(inner_ty))
             }
             TypeRef::Reference(inner, mutability) => {
-                let inner_ty = Ty::from_hir(db, module, impl_block, generics, inner);
+                let inner_ty = Ty::from_hir(db, resolver, 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, impl_block, generics, tr))
+                    .map(|tr| Ty::from_hir(db, resolver, tr))
                     .collect::<Vec<_>>();
                 let return_ty = inner_tys
                     .pop()
@@ -355,40 +347,13 @@ impl Ty {
         }
     }
 
-    pub(crate) fn from_hir_opt(
-        db: &impl HirDatabase,
-        module: &Module,
-        impl_block: Option<&ImplBlock>,
-        generics: &GenericParams,
-        type_ref: Option<&TypeRef>,
-    ) -> Self {
-        type_ref.map_or(Ty::Unknown, |t| {
-            Ty::from_hir(db, module, impl_block, generics, t)
-        })
-    }
-
-    pub(crate) fn from_hir_path(
-        db: &impl HirDatabase,
-        module: &Module,
-        impl_block: Option<&ImplBlock>,
-        generics: &GenericParams,
-        path: &Path,
-    ) -> Self {
+    pub(crate) fn from_hir_path(db: &impl HirDatabase, resolver: &Resolver, path: &Path) -> Self {
         if let Some(name) = path.as_ident() {
+            // TODO handle primitive type names in resolver as well?
             if let Some(int_ty) = primitive::UncertainIntTy::from_name(name) {
                 return Ty::Int(int_ty);
             } else if let Some(float_ty) = primitive::UncertainFloatTy::from_name(name) {
                 return Ty::Float(float_ty);
-            } else if name.as_known_name() == Some(KnownName::SelfType) {
-                // TODO pass the impl block's generics?
-                let generics = &GenericParams::default();
-                return Ty::from_hir_opt(
-                    db,
-                    module,
-                    None,
-                    generics,
-                    impl_block.map(|i| i.target_type()),
-                );
             } else if let Some(known) = name.as_known_name() {
                 match known {
                     KnownName::Bool => return Ty::Bool,
@@ -396,25 +361,40 @@ impl Ty {
                     KnownName::Str => return Ty::Str,
                     _ => {}
                 }
-            } else if let Some(generic_param) = generics.find_by_name(&name) {
+            }
+        }
+
+        // Resolve the path (in type namespace)
+        let resolution = resolver.resolve_path(db, path).take_types();
+
+        let def = match resolution {
+            Some(Resolution::Def(def)) => def,
+            Some(Resolution::LocalBinding(..)) => {
+                // this should never happen
+                panic!("path resolved to local binding in type ns");
+            }
+            Some(Resolution::GenericParam(idx)) => {
                 return Ty::Param {
-                    idx: generic_param.idx,
-                    name: generic_param.name.clone(),
+                    idx,
+                    // TODO: maybe return name in resolution?
+                    name: path
+                        .as_ident()
+                        .expect("generic param should be single-segment path")
+                        .clone(),
                 };
             }
-        }
+            Some(Resolution::SelfType(impl_block)) => {
+                return impl_block.target_ty(db);
+            }
+            None => return Ty::Unknown,
+        };
 
-        // Resolve in module (in type namespace)
-        let typable: TypableDef = match module
-            .resolve_path(db, path)
-            .take_types()
-            .and_then(|it| it.into())
-        {
+        let typable: TypableDef = match def.into() {
             None => return Ty::Unknown,
             Some(it) => it,
         };
         let ty = db.type_for_def(typable);
-        let substs = Ty::substs_from_path(db, module, impl_block, generics, path, typable);
+        let substs = Ty::substs_from_path(db, resolver, path, typable);
         ty.apply_substs(substs)
     }
 
@@ -422,10 +402,7 @@ impl Ty {
     /// `create_substs_for_ast_path` and `def_to_ty` in rustc.
     fn substs_from_path(
         db: &impl HirDatabase,
-        // the scope of the segment...
-        module: &Module,
-        impl_block: Option<&ImplBlock>,
-        outer_generics: &GenericParams,
+        resolver: &Resolver,
         path: &Path,
         resolved: TypableDef,
     ) -> Substs {
@@ -462,7 +439,7 @@ impl Ty {
             for arg in generic_args.args.iter().take(param_count) {
                 match arg {
                     GenericArg::Type(type_ref) => {
-                        let ty = Ty::from_hir(db, module, impl_block, outer_generics, type_ref);
+                        let ty = Ty::from_hir(db, resolver, type_ref);
                         substs.push(ty);
                     }
                 }
@@ -666,24 +643,17 @@ impl fmt::Display for Ty {
 /// function body.
 fn type_for_fn(db: &impl HirDatabase, def: Function) -> Ty {
     let signature = def.signature(db);
-    let module = def.module(db);
-    let impl_block = def.impl_block(db);
+    let resolver = def.resolver(db);
     let generics = def.generic_params(db);
+    let name = def.name(db);
     let input = signature
         .params()
         .iter()
-        .map(|tr| Ty::from_hir(db, &module, impl_block.as_ref(), &generics, tr))
+        .map(|tr| Ty::from_hir(db, &resolver, tr))
         .collect::<Vec<_>>();
-    let output = Ty::from_hir(
-        db,
-        &module,
-        impl_block.as_ref(),
-        &generics,
-        signature.ret_type(),
-    );
+    let output = Ty::from_hir(db, &resolver, signature.ret_type());
     let sig = Arc::new(FnSig { input, output });
     let substs = make_substs(&generics);
-    let name = def.name(db);
     Ty::FnDef {
         def,
         sig,
@@ -764,13 +734,13 @@ pub(super) fn type_for_def(db: &impl HirDatabase, def: TypableDef) -> Ty {
 
 pub(super) fn type_for_field(db: &impl HirDatabase, field: StructField) -> Ty {
     let parent_def = field.parent_def(db);
-    let (generics, module) = match parent_def {
-        VariantDef::Struct(it) => (it.generic_params(db), it.module(db)),
-        VariantDef::EnumVariant(it) => (it.parent_enum(db).generic_params(db), it.module(db)),
+    let resolver = match parent_def {
+        VariantDef::Struct(it) => it.resolver(db),
+        VariantDef::EnumVariant(it) => it.parent_enum(db).resolver(db),
     };
     let var_data = parent_def.variant_data(db);
     let type_ref = &var_data.fields().unwrap()[field.id].type_ref;
-    Ty::from_hir(db, &module, None, &generics, type_ref)
+    Ty::from_hir(db, &resolver, type_ref)
 }
 
 /// The result of type inference: A mapping from expressions and patterns to types.
@@ -814,9 +784,7 @@ impl Index<PatId> for InferenceResult {
 struct InferenceContext<'a, D: HirDatabase> {
     db: &'a D,
     body: Arc<Body>,
-    scopes: Arc<ExprScopes>,
-    module: Module,
-    impl_block: Option<ImplBlock>,
+    resolver: Resolver,
     var_unification_table: InPlaceUnificationTable<TypeVarId>,
     method_resolutions: FxHashMap<ExprId, Function>,
     field_resolutions: FxHashMap<ExprId, StructField>,
@@ -905,13 +873,7 @@ fn binary_op_rhs_expectation(op: BinaryOp, lhs_ty: Ty) -> Ty {
 }
 
 impl<'a, D: HirDatabase> InferenceContext<'a, D> {
-    fn new(
-        db: &'a D,
-        body: Arc<Body>,
-        scopes: Arc<ExprScopes>,
-        module: Module,
-        impl_block: Option<ImplBlock>,
-    ) -> Self {
+    fn new(db: &'a D, body: Arc<Body>, resolver: Resolver) -> Self {
         InferenceContext {
             method_resolutions: FxHashMap::default(),
             field_resolutions: FxHashMap::default(),
@@ -921,9 +883,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
             return_ty: Ty::Unknown, // set in collect_fn_signature
             db,
             body,
-            scopes,
-            module,
-            impl_block,
+            resolver,
         }
     }
 
@@ -940,8 +900,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
             *ty = resolved;
         }
         InferenceResult {
-            method_resolutions: mem::replace(&mut self.method_resolutions, Default::default()),
-            field_resolutions: mem::replace(&mut self.field_resolutions, Default::default()),
+            method_resolutions: self.method_resolutions,
+            field_resolutions: self.field_resolutions,
             type_of_expr: expr_types,
             type_of_pat: pat_types,
         }
@@ -964,13 +924,10 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
     }
 
     fn make_ty(&mut self, type_ref: &TypeRef) -> Ty {
-        // TODO provide generics of function
-        let generics = GenericParams::default();
         let ty = Ty::from_hir(
             self.db,
-            &self.module,
-            self.impl_block.as_ref(),
-            &generics,
+            // TODO use right resolver for block
+            &self.resolver,
             type_ref,
         );
         let ty = self.insert_type_vars(ty);
@@ -1147,38 +1104,31 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
         })
     }
 
-    fn infer_path_expr(&mut self, expr: ExprId, path: &Path) -> Option<Ty> {
-        if path.is_ident() || path.is_self() {
-            // resolve locally
-            let name = path.as_ident().cloned().unwrap_or_else(Name::self_param);
-            if let Some(scope_entry) = self.scopes.resolve_local_name(expr, name) {
-                let ty = self.type_of_pat.get(scope_entry.pat())?;
+    fn infer_path_expr(&mut self, resolver: &Resolver, path: &Path) -> Option<Ty> {
+        let resolved = resolver.resolve_path(self.db, &path).take_values()?;
+        match resolved {
+            Resolution::Def(def) => {
+                let typable: Option<TypableDef> = def.into();
+                let typable = typable?;
+                let substs = Ty::substs_from_path(self.db, &self.resolver, path, typable);
+                let ty = self.db.type_for_def(typable).apply_substs(substs);
+                let ty = self.insert_type_vars(ty);
+                Some(ty)
+            }
+            Resolution::LocalBinding(pat) => {
+                let ty = self.type_of_pat.get(pat)?;
                 let ty = self.resolve_ty_as_possible(&mut vec![], ty.clone());
-                return Some(ty);
-            };
-        };
-
-        // resolve in module
-        let typable: Option<TypableDef> = self
-            .module
-            .resolve_path(self.db, &path)
-            .take_values()?
-            .into();
-        let typable = typable?;
-        let ty = self.db.type_for_def(typable);
-        let generics = GenericParams::default();
-        let substs = Ty::substs_from_path(
-            self.db,
-            &self.module,
-            self.impl_block.as_ref(),
-            &generics,
-            path,
-            typable,
-        );
-        let ty = ty.apply_substs(substs);
-        let ty = self.insert_type_vars(ty);
-
-        Some(ty)
+                Some(ty)
+            }
+            Resolution::GenericParam(..) => {
+                // generic params can't refer to values... yet
+                None
+            }
+            Resolution::SelfType(_) => {
+                log::error!("path expr {:?} resolved to Self type in values ns", path);
+                None
+            }
+        }
     }
 
     fn resolve_variant(&mut self, path: Option<&Path>) -> (Ty, Option<VariantDef>) {
@@ -1186,26 +1136,30 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
             Some(path) => path,
             None => return (Ty::Unknown, None),
         };
-        let typable: Option<TypableDef> = self
-            .module
-            .resolve_path(self.db, &path)
-            .take_types()
-            .and_then(|it| it.into());
+        let resolver = &self.resolver;
+        let typable: Option<TypableDef> = match resolver.resolve_path(self.db, &path).take_types() {
+            Some(Resolution::Def(def)) => def.into(),
+            Some(Resolution::LocalBinding(..)) => {
+                // this cannot happen
+                log::error!("path resolved to local binding in type ns");
+                return (Ty::Unknown, None);
+            }
+            Some(Resolution::GenericParam(..)) => {
+                // generic params can't be used in struct literals
+                return (Ty::Unknown, None);
+            }
+            Some(Resolution::SelfType(..)) => {
+                // TODO this is allowed in an impl for a struct, handle this
+                return (Ty::Unknown, None);
+            }
+            None => return (Ty::Unknown, None),
+        };
         let def = match typable {
             None => return (Ty::Unknown, None),
             Some(it) => it,
         };
         // TODO remove the duplication between here and `Ty::from_path`?
-        // TODO provide generics of function
-        let generics = GenericParams::default();
-        let substs = Ty::substs_from_path(
-            self.db,
-            &self.module,
-            self.impl_block.as_ref(),
-            &generics,
-            path,
-            def,
-        );
+        let substs = Ty::substs_from_path(self.db, resolver, path, def);
         match def {
             TypableDef::Struct(s) => {
                 let ty = type_for_struct(self.db, s);
@@ -1303,12 +1257,12 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
                 path: ref p,
                 args: ref fields,
             } => self.infer_struct_pat(p.as_ref(), fields, expected),
-            Pat::Path(path) => self
-                .module
-                .resolve_path(self.db, &path)
-                .take_values()
-                .and_then(|module_def| module_def.into())
-                .map_or(Ty::Unknown, |resolved| self.db.type_for_def(resolved)),
+            Pat::Path(path) => {
+                // TODO use correct resolver for the surrounding expression
+                let resolver = self.resolver.clone();
+                self.infer_path_expr(&resolver, &path)
+                    .unwrap_or(Ty::Unknown)
+            }
             Pat::Bind {
                 mode,
                 name: _name,
@@ -1496,7 +1450,11 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
 
                 expected.ty
             }
-            Expr::Path(p) => self.infer_path_expr(tgt_expr, p).unwrap_or(Ty::Unknown),
+            Expr::Path(p) => {
+                // TODO this could be more efficient...
+                let resolver = expr::resolver_for_expr(self.body.clone(), self.db, tgt_expr);
+                self.infer_path_expr(&resolver, p).unwrap_or(Ty::Unknown)
+            }
             Expr::Continue => Ty::Never,
             Expr::Break { expr } => {
                 if let Some(expr) = expr {
@@ -1730,10 +1688,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
 pub fn infer(db: &impl HirDatabase, func: Function) -> Arc<InferenceResult> {
     db.check_canceled();
     let body = func.body(db);
-    let scopes = db.expr_scopes(func);
-    let module = func.module(db);
-    let impl_block = func.impl_block(db);
-    let mut ctx = InferenceContext::new(db, body, scopes, module, impl_block);
+    let resolver = func.resolver(db);
+    let mut ctx = InferenceContext::new(db, body, resolver);
 
     let signature = func.signature(db);
     ctx.collect_fn_signature(&signature);
diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs
index e857d6856e..2282286b0b 100644
--- a/crates/ra_hir/src/ty/method_resolution.rs
+++ b/crates/ra_hir/src/ty/method_resolution.rs
@@ -7,12 +7,10 @@ use std::sync::Arc;
 use rustc_hash::FxHashMap;
 
 use crate::{
-    HirDatabase, module_tree::ModuleId, Module, ModuleDef, Crate, Name, Function, Trait,
+    HirDatabase, module_tree::ModuleId, Module, Crate, Name, Function, Trait,
     ids::TraitId,
     impl_block::{ImplId, ImplBlock, ImplItem},
-    generics::GenericParams,
     ty::{AdtDef, Ty},
-    type_ref::TypeRef,
 };
 
 /// This is used as a key for indexing impls.
@@ -85,17 +83,10 @@ impl CrateImplBlocks {
     fn collect_recursive(&mut self, db: &impl HirDatabase, module: &Module) {
         let module_impl_blocks = db.impls_in_module(module.clone());
 
-        for (impl_id, impl_data) in module_impl_blocks.impls.iter() {
+        for (impl_id, _) in module_impl_blocks.impls.iter() {
             let impl_block = ImplBlock::from_id(Arc::clone(&module_impl_blocks), impl_id);
-            // TODO provide generics of impl
-            let generics = GenericParams::default();
-            let target_ty = Ty::from_hir(
-                db,
-                &module,
-                Some(&impl_block),
-                &generics,
-                impl_data.target_type(),
-            );
+
+            let target_ty = impl_block.target_ty(db);
 
             if let Some(target_ty_fp) = TyFingerprint::for_impl(&target_ty) {
                 self.impls
@@ -104,14 +95,11 @@ impl CrateImplBlocks {
                     .push((module.module_id, impl_id));
             }
 
-            if let Some(TypeRef::Path(path)) = impl_data.target_trait() {
-                let perns = module.resolve_path(db, path);
-                if let Some(ModuleDef::Trait(tr)) = perns.take_types() {
-                    self.impls_by_trait
-                        .entry(tr.id)
-                        .or_insert_with(Vec::new)
-                        .push((module.module_id, impl_id));
-                }
+            if let Some(tr) = impl_block.target_trait(db) {
+                self.impls_by_trait
+                    .entry(tr.id)
+                    .or_insert_with(Vec::new)
+                    .push((module.module_id, impl_id));
             }
         }
 
diff --git a/crates/ra_ide_api/src/completion/complete_path.rs b/crates/ra_ide_api/src/completion/complete_path.rs
index b33ddcde56..0b9948d4b4 100644
--- a/crates/ra_ide_api/src/completion/complete_path.rs
+++ b/crates/ra_ide_api/src/completion/complete_path.rs
@@ -1,21 +1,21 @@
 use join_to_string::join;
 
+use hir::{Docs, Resolution};
+
 use crate::{
     completion::{CompletionItem, CompletionItemKind, Completions, CompletionKind, CompletionContext},
 };
 
-use hir::Docs;
-
 pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) {
-    let (path, module) = match (&ctx.path_prefix, &ctx.module) {
-        (Some(path), Some(module)) => (path.clone(), module),
+    let path = match &ctx.path_prefix {
+        Some(path) => path.clone(),
         _ => return,
     };
-    let def_id = match module.resolve_path(ctx.db, &path).take_types() {
-        Some(it) => it,
-        None => return,
+    let def = match ctx.resolver.resolve_path(ctx.db, &path).take_types() {
+        Some(Resolution::Def(def)) => def,
+        _ => return,
     };
-    match def_id {
+    match def {
         hir::ModuleDef::Module(module) => {
             let module_scope = module.scope(ctx.db);
             for (name, res) in module_scope.entries() {
@@ -24,7 +24,7 @@ pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) {
                     ctx.source_range(),
                     name.to_string(),
                 )
-                .from_resolution(ctx, res)
+                .from_resolution(ctx, &res.def.map(hir::Resolution::Def))
                 .add_to(acc);
             }
         }
@@ -65,6 +65,17 @@ mod tests {
         check_completion(code, expected_completions, CompletionKind::Reference);
     }
 
+    #[test]
+    #[ignore] // should not complete foo, which currently doesn't work
+    fn dont_complete_current_use() {
+        check_reference_completion(
+            "dont_complete_current_use",
+            r"
+            use self::foo<|>;
+            ",
+        );
+    }
+
     #[test]
     fn completes_mod_with_docs() {
         check_reference_completion(
diff --git a/crates/ra_ide_api/src/completion/complete_scope.rs b/crates/ra_ide_api/src/completion/complete_scope.rs
index f837bb1db2..44514ab2b2 100644
--- a/crates/ra_ide_api/src/completion/complete_scope.rs
+++ b/crates/ra_ide_api/src/completion/complete_scope.rs
@@ -1,63 +1,20 @@
-use rustc_hash::FxHashSet;
-use ra_syntax::ast::AstNode;
-use crate::completion::{CompletionItem, CompletionItemKind, Completions, CompletionKind, CompletionContext};
+use crate::completion::{CompletionItem, Completions, CompletionKind, CompletionContext};
 
 pub(super) fn complete_scope(acc: &mut Completions, ctx: &CompletionContext) {
     if !ctx.is_trivial_path {
         return;
     }
-    let module = match &ctx.module {
-        Some(it) => it,
-        None => return,
-    };
-    if let Some(function) = &ctx.function {
-        let scopes = function.scopes(ctx.db);
-        complete_fn(acc, &scopes, ctx);
-    }
-
-    let module_scope = module.scope(ctx.db);
-    module_scope
-        .entries()
-        .filter(|(_name, res)| {
-            // For cases like `use self::foo<|>` don't suggest foo itself.
-            match res.import {
-                None => true,
-                Some(import) => {
-                    let source = module.import_source(ctx.db, import);
-                    !source.syntax().range().is_subrange(&ctx.leaf.range())
-                }
-            }
-        })
-        .for_each(|(name, res)| {
-            CompletionItem::new(
-                CompletionKind::Reference,
-                ctx.source_range(),
-                name.to_string(),
-            )
-            .from_resolution(ctx, res)
-            .add_to(acc)
-        });
-}
+    let names = ctx.resolver.all_names();
 
-fn complete_fn(
-    acc: &mut Completions,
-    scopes: &hir::ScopesWithSyntaxMapping,
-    ctx: &CompletionContext,
-) {
-    let mut shadowed = FxHashSet::default();
-    scopes
-        .scope_chain_for_offset(ctx.offset)
-        .flat_map(|scope| scopes.scopes.entries(scope).iter())
-        .filter(|entry| shadowed.insert(entry.name()))
-        .for_each(|entry| {
-            CompletionItem::new(
-                CompletionKind::Reference,
-                ctx.source_range(),
-                entry.name().to_string(),
-            )
-            .kind(CompletionItemKind::Binding)
-            .add_to(acc)
-        });
+    names.into_iter().for_each(|(name, res)| {
+        CompletionItem::new(
+            CompletionKind::Reference,
+            ctx.source_range(),
+            name.to_string(),
+        )
+        .from_resolution(ctx, &res)
+        .add_to(acc)
+    });
 }
 
 #[cfg(test)]
@@ -115,6 +72,30 @@ mod tests {
         );
     }
 
+    #[test]
+    fn completes_generic_params() {
+        check_reference_completion(
+            "generic_params",
+            r"
+            fn quux<T>() {
+                <|>
+            }
+            ",
+        );
+    }
+
+    #[test]
+    fn completes_generic_params_in_struct() {
+        check_reference_completion(
+            "generic_params_in_struct",
+            r"
+            struct X<T> {
+                x: <|>
+            }
+            ",
+        );
+    }
+
     #[test]
     fn completes_module_items() {
         check_reference_completion(
@@ -174,5 +155,4 @@ mod tests {
     fn completes_self_in_methods() {
         check_reference_completion("self_in_methods", r"impl S { fn foo(&self) { <|> } }")
     }
-
 }
diff --git a/crates/ra_ide_api/src/completion/completion_context.rs b/crates/ra_ide_api/src/completion/completion_context.rs
index 578af6e5b3..5d1851da64 100644
--- a/crates/ra_ide_api/src/completion/completion_context.rs
+++ b/crates/ra_ide_api/src/completion/completion_context.rs
@@ -5,7 +5,7 @@ use ra_syntax::{
     algo::{find_leaf_at_offset, find_covering_node, find_node_at_offset},
     SyntaxKind::*,
 };
-use hir::source_binder;
+use hir::{source_binder, Resolver};
 
 use crate::{db, FilePosition};
 
@@ -16,6 +16,7 @@ pub(crate) struct CompletionContext<'a> {
     pub(super) db: &'a db::RootDatabase,
     pub(super) offset: TextUnit,
     pub(super) leaf: &'a SyntaxNode,
+    pub(super) resolver: Resolver,
     pub(super) module: Option<hir::Module>,
     pub(super) function: Option<hir::Function>,
     pub(super) function_syntax: Option<&'a ast::FnDef>,
@@ -42,12 +43,14 @@ impl<'a> CompletionContext<'a> {
         original_file: &'a SourceFile,
         position: FilePosition,
     ) -> Option<CompletionContext<'a>> {
+        let resolver = source_binder::resolver_for_position(db, position);
         let module = source_binder::module_from_position(db, position);
         let leaf = find_leaf_at_offset(original_file.syntax(), position.offset).left_biased()?;
         let mut ctx = CompletionContext {
             db,
             leaf,
             offset: position.offset,
+            resolver,
             module,
             function: None,
             function_syntax: None,
diff --git a/crates/ra_ide_api/src/completion/completion_item.rs b/crates/ra_ide_api/src/completion/completion_item.rs
index d3bc148944..bada6a33bf 100644
--- a/crates/ra_ide_api/src/completion/completion_item.rs
+++ b/crates/ra_ide_api/src/completion/completion_item.rs
@@ -1,5 +1,7 @@
-use hir::{Docs, Documentation};
-use ra_syntax::TextRange;
+use hir::{Docs, Documentation, PerNs, Resolution};
+use ra_syntax::{
+    TextRange,
+};
 use ra_text_edit::TextEdit;
 use test_utils::tested_by;
 
@@ -48,6 +50,7 @@ pub enum CompletionItemKind {
     Trait,
     TypeAlias,
     Method,
+    TypeParam,
 }
 
 #[derive(Debug, PartialEq, Eq, Copy, Clone)]
@@ -207,23 +210,34 @@ impl Builder {
     pub(super) fn from_resolution(
         mut self,
         ctx: &CompletionContext,
-        resolution: &hir::Resolution,
+        resolution: &PerNs<Resolution>,
     ) -> Builder {
-        let def = resolution.def.take_types().or(resolution.def.take_values());
+        use hir::ModuleDef::*;
+
+        let def = resolution
+            .as_ref()
+            .take_types()
+            .or(resolution.as_ref().take_values());
         let def = match def {
             None => return self,
             Some(it) => it,
         };
         let (kind, docs) = match def {
-            hir::ModuleDef::Module(it) => (CompletionItemKind::Module, it.docs(ctx.db)),
-            hir::ModuleDef::Function(func) => return self.from_function(ctx, func),
-            hir::ModuleDef::Struct(it) => (CompletionItemKind::Struct, it.docs(ctx.db)),
-            hir::ModuleDef::Enum(it) => (CompletionItemKind::Enum, it.docs(ctx.db)),
-            hir::ModuleDef::EnumVariant(it) => (CompletionItemKind::EnumVariant, it.docs(ctx.db)),
-            hir::ModuleDef::Const(it) => (CompletionItemKind::Const, it.docs(ctx.db)),
-            hir::ModuleDef::Static(it) => (CompletionItemKind::Static, it.docs(ctx.db)),
-            hir::ModuleDef::Trait(it) => (CompletionItemKind::Trait, it.docs(ctx.db)),
-            hir::ModuleDef::Type(it) => (CompletionItemKind::TypeAlias, it.docs(ctx.db)),
+            Resolution::Def(Module(it)) => (CompletionItemKind::Module, it.docs(ctx.db)),
+            Resolution::Def(Function(func)) => return self.from_function(ctx, *func),
+            Resolution::Def(Struct(it)) => (CompletionItemKind::Struct, it.docs(ctx.db)),
+            Resolution::Def(Enum(it)) => (CompletionItemKind::Enum, it.docs(ctx.db)),
+            Resolution::Def(EnumVariant(it)) => (CompletionItemKind::EnumVariant, it.docs(ctx.db)),
+            Resolution::Def(Const(it)) => (CompletionItemKind::Const, it.docs(ctx.db)),
+            Resolution::Def(Static(it)) => (CompletionItemKind::Static, it.docs(ctx.db)),
+            Resolution::Def(Trait(it)) => (CompletionItemKind::Trait, it.docs(ctx.db)),
+            Resolution::Def(Type(it)) => (CompletionItemKind::TypeAlias, it.docs(ctx.db)),
+            Resolution::GenericParam(..) => (CompletionItemKind::TypeParam, None),
+            Resolution::LocalBinding(..) => (CompletionItemKind::Binding, None),
+            Resolution::SelfType(..) => (
+                CompletionItemKind::TypeParam, // (does this need its own kind?)
+                None,
+            ),
         };
         self.kind = Some(kind);
         self.documentation = docs;
diff --git a/crates/ra_ide_api/src/completion/snapshots/completion_item__generic_params.snap b/crates/ra_ide_api/src/completion/snapshots/completion_item__generic_params.snap
new file mode 100644
index 0000000000..71cb55a5bc
--- /dev/null
+++ b/crates/ra_ide_api/src/completion/snapshots/completion_item__generic_params.snap
@@ -0,0 +1,40 @@
+---
+created: "2019-02-01T22:20:40.580128393+00:00"
+creator: insta@0.5.3
+expression: kind_completions
+source: crates/ra_ide_api/src/completion/completion_item.rs
+---
+[
+    CompletionItem {
+        completion_kind: Reference,
+        label: "T",
+        kind: Some(
+            TypeParam
+        ),
+        detail: None,
+        documentation: None,
+        lookup: None,
+        insert_text: None,
+        insert_text_format: PlainText,
+        source_range: [44; 44),
+        text_edit: None
+    },
+    CompletionItem {
+        completion_kind: Reference,
+        label: "quux",
+        kind: Some(
+            Function
+        ),
+        detail: Some(
+            "fn quux<T>()"
+        ),
+        documentation: None,
+        lookup: None,
+        insert_text: Some(
+            "quux()$0"
+        ),
+        insert_text_format: Snippet,
+        source_range: [44; 44),
+        text_edit: None
+    }
+]
diff --git a/crates/ra_ide_api/src/completion/snapshots/completion_item__generic_params_in_struct.snap b/crates/ra_ide_api/src/completion/snapshots/completion_item__generic_params_in_struct.snap
new file mode 100644
index 0000000000..a35c0cd13a
--- /dev/null
+++ b/crates/ra_ide_api/src/completion/snapshots/completion_item__generic_params_in_struct.snap
@@ -0,0 +1,36 @@
+---
+created: "2019-02-01T22:23:21.508620224+00:00"
+creator: insta@0.5.3
+expression: kind_completions
+source: crates/ra_ide_api/src/completion/completion_item.rs
+---
+[
+    CompletionItem {
+        completion_kind: Reference,
+        label: "T",
+        kind: Some(
+            TypeParam
+        ),
+        detail: None,
+        documentation: None,
+        lookup: None,
+        insert_text: None,
+        insert_text_format: PlainText,
+        source_range: [46; 46),
+        text_edit: None
+    },
+    CompletionItem {
+        completion_kind: Reference,
+        label: "X",
+        kind: Some(
+            Struct
+        ),
+        detail: None,
+        documentation: None,
+        lookup: None,
+        insert_text: None,
+        insert_text_format: PlainText,
+        source_range: [46; 46),
+        text_edit: None
+    }
+]
diff --git a/crates/ra_ide_api/src/completion/snapshots/completion_item__self_in_methods.snap b/crates/ra_ide_api/src/completion/snapshots/completion_item__self_in_methods.snap
index 6a49e325c1..ba1d4abbd5 100644
--- a/crates/ra_ide_api/src/completion/snapshots/completion_item__self_in_methods.snap
+++ b/crates/ra_ide_api/src/completion/snapshots/completion_item__self_in_methods.snap
@@ -1,10 +1,24 @@
 ---
-created: "2019-01-23T05:27:32.422259+00:00"
-creator: insta@0.4.0
+created: "2019-01-27T20:17:10.051725945+00:00"
+creator: insta@0.5.2
 expression: kind_completions
 source: crates/ra_ide_api/src/completion/completion_item.rs
 ---
 [
+    CompletionItem {
+        completion_kind: Reference,
+        label: "Self",
+        kind: Some(
+            TypeParam
+        ),
+        detail: None,
+        documentation: None,
+        lookup: None,
+        insert_text: None,
+        insert_text_format: PlainText,
+        source_range: [25; 25),
+        text_edit: None
+    },
     CompletionItem {
         completion_kind: Reference,
         label: "self",
diff --git a/crates/ra_ide_api/src/goto_definition.rs b/crates/ra_ide_api/src/goto_definition.rs
index 2a20c20ee9..88efcea2a5 100644
--- a/crates/ra_ide_api/src/goto_definition.rs
+++ b/crates/ra_ide_api/src/goto_definition.rs
@@ -4,6 +4,7 @@ use ra_syntax::{
     algo::find_node_at_offset,
 };
 use test_utils::tested_by;
+use hir::Resolution;
 
 use crate::{FilePosition, NavigationTarget, db::RootDatabase, RangeInfo};
 
@@ -48,14 +49,7 @@ pub(crate) fn reference_definition(
     if let Some(function) =
         hir::source_binder::function_from_child_node(db, file_id, name_ref.syntax())
     {
-        let scope = function.scopes(db);
-        // First try to resolve the symbol locally
-        if let Some(entry) = scope.resolve_local_name(name_ref) {
-            let nav = NavigationTarget::from_scope_entry(file_id, &entry);
-            return Exact(nav);
-        };
-
-        // Next check if it is a method
+        // Check if it is a method
         if let Some(method_call) = name_ref
             .syntax()
             .parent()
@@ -86,19 +80,37 @@ pub(crate) fn reference_definition(
             };
         }
     }
-    // Then try module name resolution
-    if let Some(module) = hir::source_binder::module_from_child_node(db, file_id, name_ref.syntax())
+    // Try name resolution
+    let resolver = hir::source_binder::resolver_for_node(db, file_id, name_ref.syntax());
+    if let Some(path) = name_ref
+        .syntax()
+        .ancestors()
+        .find_map(ast::Path::cast)
+        .and_then(hir::Path::from_ast)
     {
-        if let Some(path) = name_ref
-            .syntax()
-            .ancestors()
-            .find_map(ast::Path::cast)
-            .and_then(hir::Path::from_ast)
-        {
-            let resolved = module.resolve_path(db, &path);
-            if let Some(def_id) = resolved.take_types().or(resolved.take_values()) {
-                return Exact(NavigationTarget::from_def(db, def_id));
+        let resolved = resolver.resolve_path(db, &path);
+        match resolved.clone().take_types().or(resolved.take_values()) {
+            Some(Resolution::Def(def)) => return Exact(NavigationTarget::from_def(db, def)),
+            Some(Resolution::LocalBinding(pat)) => {
+                let body = resolver.body().expect("no body for local binding");
+                let syntax_mapping = body.syntax_mapping(db);
+                let ptr = syntax_mapping
+                    .pat_syntax(pat)
+                    .expect("pattern not found in syntax mapping");
+                let name = path
+                    .as_ident()
+                    .cloned()
+                    .expect("local binding from a multi-segment path");
+                let nav = NavigationTarget::from_scope_entry(file_id, name, ptr);
+                return Exact(nav);
+            }
+            Some(Resolution::GenericParam(..)) => {
+                // TODO go to the generic param def
+            }
+            Some(Resolution::SelfType(_impl_block)) => {
+                // TODO go to the implemented type
             }
+            None => {}
         }
     }
     // If that fails try the index based approach.
diff --git a/crates/ra_ide_api/src/navigation_target.rs b/crates/ra_ide_api/src/navigation_target.rs
index 5ccb5cc2e3..617908aedf 100644
--- a/crates/ra_ide_api/src/navigation_target.rs
+++ b/crates/ra_ide_api/src/navigation_target.rs
@@ -1,9 +1,9 @@
 use ra_db::FileId;
 use ra_syntax::{
-    SyntaxNode, AstNode, SmolStr, TextRange, ast,
+    SyntaxNode, SyntaxNodePtr, AstNode, SmolStr, TextRange, ast,
     SyntaxKind::{self, NAME},
 };
-use hir::{ModuleSource, FieldSource};
+use hir::{ModuleSource, FieldSource, Name};
 
 use crate::{FileSymbol, db::RootDatabase};
 
@@ -58,12 +58,13 @@ impl NavigationTarget {
 
     pub(crate) fn from_scope_entry(
         file_id: FileId,
-        entry: &hir::ScopeEntryWithSyntax,
+        name: Name,
+        ptr: SyntaxNodePtr,
     ) -> NavigationTarget {
         NavigationTarget {
             file_id,
-            name: entry.name().to_string().into(),
-            full_range: entry.ptr().range(),
+            name: name.to_string().into(),
+            full_range: ptr.range(),
             focus_range: None,
             kind: NAME,
         }
diff --git a/crates/ra_lsp_server/src/conv.rs b/crates/ra_lsp_server/src/conv.rs
index c033ecdeaa..17fa073406 100644
--- a/crates/ra_lsp_server/src/conv.rs
+++ b/crates/ra_lsp_server/src/conv.rs
@@ -70,6 +70,7 @@ impl Conv for CompletionItemKind {
             CompletionItemKind::Const => Constant,
             CompletionItemKind::Static => Value,
             CompletionItemKind::Method => Method,
+            CompletionItemKind::TypeParam => TypeParameter,
         }
     }
 }


Test patch:
diff --git a/crates/ra_hir/src/nameres/tests.rs b/crates/ra_hir/src/nameres/tests.rs
index 1ce7bd146d..0e0683db77 100644
--- a/crates/ra_hir/src/nameres/tests.rs
+++ b/crates/ra_hir/src/nameres/tests.rs
@@ -5,11 +5,12 @@ use relative_path::RelativePath;
 use test_utils::{assert_eq_text, covers};
 
 use crate::{
-    ItemMap, Resolution,
+    ItemMap,
     PersistentHirDatabase,
     mock::MockDatabase,
     module_tree::ModuleId,
 };
+use super::Resolution;
 
 fn item_map(fixture: &str) -> (Arc<ItemMap>, ModuleId) {
     let (db, pos) = MockDatabase::with_position(fixture);
diff --git a/crates/ra_hir/src/ty/snapshots/tests__infer_function_generics.snap b/crates/ra_hir/src/ty/snapshots/tests__infer_function_generics.snap
index 8ff6e55a6b..91c48897cf 100644
--- a/crates/ra_hir/src/ty/snapshots/tests__infer_function_generics.snap
+++ b/crates/ra_hir/src/ty/snapshots/tests__infer_function_generics.snap
@@ -1,12 +1,12 @@
 ---
-created: "2019-01-26T18:16:16.530712344+00:00"
+created: "2019-01-27T14:52:29.934503829+00:00"
 creator: insta@0.5.2
 expression: "&result"
 source: crates/ra_hir/src/ty/tests.rs
 ---
-[10; 11) 't': [unknown]
-[21; 26) '{ t }': [unknown]
-[23; 24) 't': [unknown]
+[10; 11) 't': T
+[21; 26) '{ t }': T
+[23; 24) 't': T
 [38; 98) '{     ...(1); }': ()
 [44; 46) 'id': fn id<u32>(T) -> T
 [44; 52) 'id(1u32)': u32
diff --git a/crates/ra_hir/src/ty/snapshots/tests__infer_generic_chain.snap b/crates/ra_hir/src/ty/snapshots/tests__infer_generic_chain.snap
index f21bffa754..626f312525 100644
--- a/crates/ra_hir/src/ty/snapshots/tests__infer_generic_chain.snap
+++ b/crates/ra_hir/src/ty/snapshots/tests__infer_generic_chain.snap
@@ -1,5 +1,5 @@
 ---
-created: "2019-01-26T17:46:03.866825843+00:00"
+created: "2019-01-27T14:52:29.938713255+00:00"
 creator: insta@0.5.2
 expression: "&result"
 source: crates/ra_hir/src/ty/tests.rs
@@ -8,9 +8,9 @@ source: crates/ra_hir/src/ty/tests.rs
 [65; 87) '{     ...     }': [unknown]
 [75; 79) 'self': A<[unknown]>
 [75; 81) 'self.x': [unknown]
-[99; 100) 't': [unknown]
-[110; 115) '{ t }': [unknown]
-[112; 113) 't': [unknown]
+[99; 100) 't': T
+[110; 115) '{ t }': T
+[112; 113) 't': T
 [135; 261) '{     ....x() }': i128
 [146; 147) 'x': i32
 [150; 151) '1': i32
diff --git a/crates/ra_hir/src/ty/snapshots/tests__infer_type_param.snap b/crates/ra_hir/src/ty/snapshots/tests__infer_type_param.snap
index a993232642..216d1e41f1 100644
--- a/crates/ra_hir/src/ty/snapshots/tests__infer_type_param.snap
+++ b/crates/ra_hir/src/ty/snapshots/tests__infer_type_param.snap
@@ -1,15 +1,15 @@
 ---
-created: "2019-01-27T16:54:18.368427685+00:00"
+created: "2019-01-27T20:38:32.153717698+00:00"
 creator: insta@0.5.2
 expression: "&result"
 source: crates/ra_hir/src/ty/tests.rs
 ---
-[10; 11) 'x': [unknown]
-[21; 30) '{     x }': [unknown]
-[27; 28) 'x': [unknown]
-[44; 45) 'x': &[unknown]
-[56; 65) '{     x }': &[unknown]
-[62; 63) 'x': &[unknown]
+[10; 11) 'x': T
+[21; 30) '{     x }': T
+[27; 28) 'x': T
+[44; 45) 'x': &T
+[56; 65) '{     x }': &T
+[62; 63) 'x': &T
 [77; 157) '{     ...(1); }': ()
 [87; 88) 'y': u32
 [91; 96) '10u32': u32