Repository: rust-analyzer/rust-analyzer
Pull request #330 (2018-12-25 10:06:17)

WIP: introduce hir::Name
Currently we are using `SmolStr` throughout the hir as a name, but that is really suboptimal choice: we'll probably want some kind of interning in the future, and we'll definitely need to add hygene info to names. This PR aims to replace strings with a slightly more abstract `Name` type. 


Patch:
diff --git a/crates/ra_analysis/src/imp.rs b/crates/ra_analysis/src/imp.rs
index 38a5c1a7d1..0471a2fca5 100644
--- a/crates/ra_analysis/src/imp.rs
+++ b/crates/ra_analysis/src/imp.rs
@@ -243,7 +243,7 @@ impl AnalysisImpl {
                     rr.add_resolution(
                         position.file_id,
                         FileSymbol {
-                            name: entry.name().clone(),
+                            name: entry.name().to_string().into(),
                             node_range: entry.ptr().range(),
                             kind: NAME,
                         },
@@ -261,23 +261,21 @@ impl AnalysisImpl {
             let mut rr = ReferenceResolution::new(name.syntax().range());
             if let Some(module) = name.syntax().parent().and_then(ast::Module::cast) {
                 if module.has_semi() {
-                    let parent_module =
-                        source_binder::module_from_file_id(&*self.db, position.file_id)?;
-                    let child_name = module.name();
-                    match (parent_module, child_name) {
-                        (Some(parent_module), Some(child_name)) => {
-                            if let Some(child) = parent_module.child(&child_name.text()) {
-                                let file_id = child.source().file_id();
-                                let symbol = FileSymbol {
-                                    name: child_name.text(),
-                                    node_range: TextRange::offset_len(0.into(), 0.into()),
-                                    kind: MODULE,
-                                };
-                                rr.add_resolution(file_id, symbol);
-                                return Ok(Some(rr));
-                            }
-                        }
-                        _ => (),
+                    if let Some(child_module) =
+                        source_binder::module_from_declaration(&*self.db, position.file_id, module)?
+                    {
+                        let file_id = child_module.source().file_id();
+                        let name = match child_module.name() {
+                            Some(name) => name.to_string().into(),
+                            None => "".into(),
+                        };
+                        let symbol = FileSymbol {
+                            name,
+                            node_range: TextRange::offset_len(0.into(), 0.into()),
+                            kind: MODULE,
+                        };
+                        rr.add_resolution(file_id, symbol);
+                        return Ok(Some(rr));
                     }
                 }
             }
diff --git a/crates/ra_db/src/lib.rs b/crates/ra_db/src/lib.rs
index 1f7c9187be..3028db17c2 100644
--- a/crates/ra_db/src/lib.rs
+++ b/crates/ra_db/src/lib.rs
@@ -14,7 +14,7 @@ pub use crate::{
     cancelation::{Canceled, Cancelable},
     syntax_ptr::LocalSyntaxPtr,
     input::{
-        FilesDatabase, FileId, CrateId, SourceRoot, SourceRootId, CrateGraph,
+        FilesDatabase, FileId, CrateId, SourceRoot, SourceRootId, CrateGraph, Dependency,
         FileTextQuery, FileSourceRootQuery, SourceRootQuery, LocalRootsQuery, LibraryRootsQuery, CrateGraphQuery,
         FileRelativePathQuery
     },
diff --git a/crates/ra_hir/src/function/scope.rs b/crates/ra_hir/src/function/scope.rs
index a1a5809797..3e4cfad0c4 100644
--- a/crates/ra_hir/src/function/scope.rs
+++ b/crates/ra_hir/src/function/scope.rs
@@ -1,7 +1,7 @@
 use rustc_hash::{FxHashMap, FxHashSet};
 
 use ra_syntax::{
-    AstNode, SmolStr, SyntaxNodeRef, TextUnit, TextRange,
+    AstNode, SyntaxNodeRef, TextUnit, TextRange,
     algo::generate,
     ast::{self, ArgListOwner, LoopBodyOwner, NameOwner},
 };
@@ -9,6 +9,7 @@ use ra_db::LocalSyntaxPtr;
 
 use crate::{
     arena::{Arena, Id},
+    Name, AsName,
 };
 
 pub(crate) type ScopeId = Id<ScopeData>;
@@ -22,7 +23,7 @@ pub struct FnScopes {
 
 #[derive(Debug, PartialEq, Eq)]
 pub struct ScopeEntry {
-    name: SmolStr,
+    name: Name,
     ptr: LocalSyntaxPtr,
 }
 
@@ -101,11 +102,12 @@ impl FnScopes {
 
     pub fn resolve_local_name<'a>(&'a self, name_ref: ast::NameRef) -> Option<&'a ScopeEntry> {
         let mut shadowed = FxHashSet::default();
+        let name = name_ref.as_name();
         let ret = self
             .scope_chain(name_ref.syntax())
             .flat_map(|scope| self.entries(scope).iter())
             .filter(|entry| shadowed.insert(entry.name()))
-            .filter(|entry| entry.name() == &name_ref.text())
+            .filter(|entry| entry.name() == &name)
             .nth(0);
         ret
     }
@@ -170,14 +172,14 @@ impl FnScopes {
 
 impl ScopeEntry {
     fn new(pat: ast::BindPat) -> Option<ScopeEntry> {
-        let name = pat.name()?;
+        let name = pat.name()?.as_name();
         let res = ScopeEntry {
-            name: name.text(),
+            name,
             ptr: LocalSyntaxPtr::new(pat.syntax()),
         };
         Some(res)
     }
-    pub fn name(&self) -> &SmolStr {
+    pub fn name(&self) -> &Name {
         &self.name
     }
     pub fn ptr(&self) -> LocalSyntaxPtr {
@@ -334,7 +336,7 @@ pub struct ReferenceDescriptor {
 mod tests {
     use ra_editor::find_node_at_offset;
     use ra_syntax::SourceFileNode;
-    use test_utils::extract_offset;
+    use test_utils::{extract_offset, assert_eq_text};
 
     use super::*;
 
@@ -355,9 +357,11 @@ mod tests {
         let actual = scopes
             .scope_chain(marker.syntax())
             .flat_map(|scope| scopes.entries(scope))
-            .map(|it| it.name())
-            .collect::<Vec<_>>();
-        assert_eq!(actual.as_slice(), expected);
+            .map(|it| it.name().to_string())
+            .collect::<Vec<_>>()
+            .join("\n");
+        let expected = expected.join("\n");
+        assert_eq_text!(&actual, &expected);
     }
 
     #[test]
diff --git a/crates/ra_hir/src/krate.rs b/crates/ra_hir/src/krate.rs
index 1196dcef17..89b1e639ef 100644
--- a/crates/ra_hir/src/krate.rs
+++ b/crates/ra_hir/src/krate.rs
@@ -1,7 +1,6 @@
-use ra_syntax::SmolStr;
 pub use ra_db::CrateId;
 
-use crate::{HirDatabase, Module, Cancelable};
+use crate::{HirDatabase, Module, Cancelable, Name, AsName};
 
 /// 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
@@ -14,7 +13,7 @@ pub struct Crate {
 #[derive(Debug)]
 pub struct CrateDependency {
     pub krate: Crate,
-    pub name: SmolStr,
+    pub name: Name,
 }
 
 impl Crate {
@@ -27,7 +26,7 @@ impl Crate {
             .dependencies(self.crate_id)
             .map(|dep| {
                 let krate = Crate::new(dep.crate_id());
-                let name = dep.name.clone();
+                let name = dep.as_name();
                 CrateDependency { krate, name }
             })
             .collect()
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs
index f1cc0ccd08..5bbb09c01c 100644
--- a/crates/ra_hir/src/lib.rs
+++ b/crates/ra_hir/src/lib.rs
@@ -22,6 +22,7 @@ mod path;
 mod arena;
 pub mod source_binder;
 
+mod name;
 mod krate;
 mod module;
 mod function;
@@ -37,10 +38,12 @@ use ra_db::{LocationIntener, SourceRootId, FileId, Cancelable};
 use crate::{
     db::HirDatabase,
     arena::{Arena, Id},
+    name::{AsName, KnownName},
 };
 
 pub use self::{
     path::{Path, PathKind},
+    name::Name,
     krate::Crate,
     module::{Module, ModuleId, Problem, nameres::{ItemMap, PerNs, Namespace}, ModuleScope, Resolution},
     function::{Function, FnScopes},
diff --git a/crates/ra_hir/src/module.rs b/crates/ra_hir/src/module.rs
index b9d36f01f0..43413acb8b 100644
--- a/crates/ra_hir/src/module.rs
+++ b/crates/ra_hir/src/module.rs
@@ -7,13 +7,14 @@ use log;
 use ra_syntax::{
     algo::generate,
     ast::{self, AstNode, NameOwner},
-    SmolStr, SyntaxNode,
+    SyntaxNode,
 };
 use ra_db::{SourceRootId, FileId, Cancelable};
 use relative_path::RelativePathBuf;
 
 use crate::{
     DefKind, DefLoc, DefId, Path, PathKind, HirDatabase, SourceItemId, SourceFileItemId, Crate,
+    Name,
     arena::{Arena, Id},
 };
 
@@ -84,7 +85,7 @@ impl Module {
     }
 
     /// `name` is `None` for the crate's root module
-    pub fn name(&self) -> Option<SmolStr> {
+    pub fn name(&self) -> Option<&Name> {
         let link = self.module_id.parent_link(&self.tree)?;
         Some(link.name(&self.tree))
     }
@@ -100,7 +101,7 @@ impl Module {
     }
 
     /// Finds a child module with the specified name.
-    pub fn child(&self, name: &str) -> Option<Module> {
+    pub fn child(&self, name: &Name) -> Option<Module> {
         let child_id = self.module_id.child(&self.tree, name)?;
         Some(Module {
             module_id: child_id,
@@ -230,15 +231,15 @@ impl ModuleId {
             .last()
             .unwrap()
     }
-    fn child(self, tree: &ModuleTree, name: &str) -> Option<ModuleId> {
+    fn child(self, tree: &ModuleTree, name: &Name) -> Option<ModuleId> {
         let link = tree.mods[self]
             .children
             .iter()
             .map(|&it| &tree.links[it])
-            .find(|it| it.name == name)?;
+            .find(|it| it.name == *name)?;
         Some(*link.points_to.first()?)
     }
-    fn children<'a>(self, tree: &'a ModuleTree) -> impl Iterator<Item = (SmolStr, ModuleId)> + 'a {
+    fn children<'a>(self, tree: &'a ModuleTree) -> impl Iterator<Item = (Name, ModuleId)> + 'a {
         tree.mods[self].children.iter().filter_map(move |&it| {
             let link = &tree.links[it];
             let module = *link.points_to.first()?;
@@ -263,8 +264,8 @@ impl LinkId {
     fn owner(self, tree: &ModuleTree) -> ModuleId {
         tree.links[self].owner
     }
-    fn name(self, tree: &ModuleTree) -> SmolStr {
-        tree.links[self].name.clone()
+    fn name(self, tree: &ModuleTree) -> &Name {
+        &tree.links[self].name
     }
     fn bind_source<'a>(self, tree: &ModuleTree, db: &impl HirDatabase) -> ast::ModuleNode {
         let owner = self.owner(tree);
@@ -328,7 +329,7 @@ impl ModuleSource {
 #[derive(Hash, Debug, PartialEq, Eq)]
 struct LinkData {
     owner: ModuleId,
-    name: SmolStr,
+    name: Name,
     points_to: Vec<ModuleId>,
     problem: Option<Problem>,
 }
diff --git a/crates/ra_hir/src/module/imp.rs b/crates/ra_hir/src/module/imp.rs
index 748fdb64e2..eded85a633 100644
--- a/crates/ra_hir/src/module/imp.rs
+++ b/crates/ra_hir/src/module/imp.rs
@@ -1,16 +1,13 @@
 use std::sync::Arc;
 
-use ra_syntax::{
-    ast::{self, NameOwner},
-    SmolStr,
-};
+use ra_syntax::ast::{self, NameOwner};
 use relative_path::RelativePathBuf;
 use rustc_hash::{FxHashMap, FxHashSet};
 use arrayvec::ArrayVec;
 use ra_db::{SourceRoot, SourceRootId, Cancelable, FileId};
 
 use crate::{
-    HirDatabase,
+    HirDatabase, Name, AsName,
 };
 
 use super::{
@@ -20,12 +17,12 @@ use super::{
 
 #[derive(Clone, Hash, PartialEq, Eq, Debug)]
 pub enum Submodule {
-    Declaration(SmolStr),
-    Definition(SmolStr, ModuleSource),
+    Declaration(Name),
+    Definition(Name, ModuleSource),
 }
 
 impl Submodule {
-    fn name(&self) -> &SmolStr {
+    fn name(&self) -> &Name {
         match self {
             Submodule::Declaration(name) => name,
             Submodule::Definition(name, _) => name,
@@ -35,14 +32,14 @@ impl Submodule {
 
 pub(crate) fn modules<'a>(
     root: impl ast::ModuleItemOwner<'a>,
-) -> impl Iterator<Item = (SmolStr, ast::Module<'a>)> {
+) -> impl Iterator<Item = (Name, ast::Module<'a>)> {
     root.items()
         .filter_map(|item| match item {
             ast::ModuleItem::Module(m) => Some(m),
             _ => None,
         })
         .filter_map(|module| {
-            let name = module.name()?.text();
+            let name = module.name()?.as_name();
             Some((name, module))
         })
 }
@@ -155,7 +152,7 @@ fn build_subtree(
 fn resolve_submodule(
     db: &impl HirDatabase,
     source: ModuleSource,
-    name: &SmolStr,
+    name: &Name,
 ) -> (Vec<FileId>, Option<Problem>) {
     // FIXME: handle submodules of inline modules properly
     let file_id = source.file_id();
diff --git a/crates/ra_hir/src/module/nameres.rs b/crates/ra_hir/src/module/nameres.rs
index 98cd225dde..68eb02a980 100644
--- a/crates/ra_hir/src/module/nameres.rs
+++ b/crates/ra_hir/src/module/nameres.rs
@@ -14,14 +14,12 @@
 //! modifications (that is, typing inside a function shold not change IMIs),
 //! such that the results of name resolution can be preserved unless the module
 //! structure itself is modified.
-use std::{
-    sync::Arc,
-};
+use std::sync::Arc;
 
 use rustc_hash::FxHashMap;
 use ra_syntax::{
     TextRange,
-    SmolStr, SyntaxKind::{self, *},
+    SyntaxKind::{self, *},
     ast::{self, AstNode}
 };
 use ra_db::SourceRootId;
@@ -32,6 +30,7 @@ use crate::{
     SourceItemId, SourceFileItemId, SourceFileItems,
     Path, PathKind,
     HirDatabase, Crate,
+    Name, AsName,
     module::{Module, ModuleId, ModuleTree},
 };
 
@@ -45,14 +44,14 @@ pub struct ItemMap {
 
 #[derive(Debug, Default, PartialEq, Eq, Clone)]
 pub struct ModuleScope {
-    items: FxHashMap<SmolStr, Resolution>,
+    items: FxHashMap<Name, Resolution>,
 }
 
 impl ModuleScope {
-    pub fn entries<'a>(&'a self) -> impl Iterator<Item = (&'a SmolStr, &'a Resolution)> + 'a {
+    pub fn entries<'a>(&'a self) -> impl Iterator<Item = (&'a Name, &'a Resolution)> + 'a {
         self.items.iter()
     }
-    pub fn get(&self, name: &SmolStr) -> Option<&Resolution> {
+    pub fn get(&self, name: &Name) -> Option<&Resolution> {
         self.items.get(name)
     }
 }
@@ -72,7 +71,7 @@ pub struct InputModuleItems {
 #[derive(Debug, PartialEq, Eq)]
 struct ModuleItem {
     id: SourceFileItemId,
-    name: SmolStr,
+    name: Name,
     kind: SyntaxKind,
     vis: Vis,
 }
@@ -260,7 +259,7 @@ impl InputModuleItems {
 
 impl ModuleItem {
     fn new<'a>(file_items: &SourceFileItems, item: impl ast::NameOwner<'a>) -> Option<ModuleItem> {
-        let name = item.name()?.text();
+        let name = item.name()?.as_name();
         let kind = item.syntax().kind();
         let vis = Vis::Other;
         let id = file_items.id_of_unchecked(item.syntax());
@@ -328,7 +327,11 @@ where
                 for dep in krate.dependencies(self.db) {
                     if let Some(module) = dep.krate.root_module(self.db)? {
                         let def_id = module.def_id(self.db);
-                        self.add_module_item(&mut module_items, dep.name, PerNs::types(def_id));
+                        self.add_module_item(
+                            &mut module_items,
+                            dep.name.clone(),
+                            PerNs::types(def_id),
+                        );
                     }
                 }
             };
@@ -389,7 +392,7 @@ where
         Ok(())
     }
 
-    fn add_module_item(&self, module_items: &mut ModuleScope, name: SmolStr, def_id: PerNs<DefId>) {
+    fn add_module_item(&self, module_items: &mut ModuleScope, name: Name, def_id: PerNs<DefId>) {
         let resolution = Resolution {
             def_id,
             import: None,
diff --git a/crates/ra_hir/src/name.rs b/crates/ra_hir/src/name.rs
new file mode 100644
index 0000000000..e4fc141a67
--- /dev/null
+++ b/crates/ra_hir/src/name.rs
@@ -0,0 +1,97 @@
+use std::fmt;
+
+use ra_syntax::{ast, SmolStr};
+
+/// `Name` is a wrapper around string, which is used in hir for both references
+/// and declarations. In theory, names should also carry hygene info, but we are
+/// not there yet!
+#[derive(Clone, PartialEq, Eq, Hash)]
+pub struct Name {
+    text: SmolStr,
+}
+
+impl fmt::Display for Name {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        fmt::Display::fmt(&self.text, f)
+    }
+}
+
+impl fmt::Debug for Name {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        fmt::Debug::fmt(&self.text, f)
+    }
+}
+
+impl Name {
+    pub(crate) fn as_known_name(&self) -> Option<KnownName> {
+        let name = match self.text.as_str() {
+            "isize" => KnownName::Isize,
+            "i8" => KnownName::I8,
+            "i16" => KnownName::I16,
+            "i32" => KnownName::I32,
+            "i64" => KnownName::I64,
+            "i128" => KnownName::I128,
+            "usize" => KnownName::Usize,
+            "u8" => KnownName::U8,
+            "u16" => KnownName::U16,
+            "u32" => KnownName::U32,
+            "u64" => KnownName::U64,
+            "u128" => KnownName::U128,
+            "f32" => KnownName::F32,
+            "f64" => KnownName::F64,
+            _ => return None,
+        };
+        Some(name)
+    }
+
+    fn new(text: SmolStr) -> Name {
+        Name { text }
+    }
+}
+
+pub(crate) trait AsName {
+    fn as_name(&self) -> Name;
+}
+
+impl AsName for ast::NameRef<'_> {
+    fn as_name(&self) -> Name {
+        Name::new(self.text())
+    }
+}
+
+impl AsName for ast::Name<'_> {
+    fn as_name(&self) -> Name {
+        Name::new(self.text())
+    }
+}
+
+impl AsName for ra_db::Dependency {
+    fn as_name(&self) -> Name {
+        Name::new(self.name.clone())
+    }
+}
+
+// Ideally, should be replaced with
+// ```
+// const ISIZE: Name = Name::new("isize")
+// ```
+// but const-fn is not that powerful yet.
+#[derive(Debug)]
+pub(crate) enum KnownName {
+    Isize,
+    I8,
+    I16,
+    I32,
+    I64,
+    I128,
+
+    Usize,
+    U8,
+    U16,
+    U32,
+    U64,
+    U128,
+
+    F32,
+    F64,
+}
diff --git a/crates/ra_hir/src/path.rs b/crates/ra_hir/src/path.rs
index 0b260072cc..93f7203fe2 100644
--- a/crates/ra_hir/src/path.rs
+++ b/crates/ra_hir/src/path.rs
@@ -1,9 +1,11 @@
-use ra_syntax::{SmolStr, ast, AstNode, TextRange};
+use ra_syntax::{ast, AstNode, TextRange};
+
+use crate::{Name, AsName};
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub struct Path {
     pub kind: PathKind,
-    pub segments: Vec<SmolStr>,
+    pub segments: Vec<Name>,
 }
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@@ -29,7 +31,7 @@ impl Path {
         loop {
             let segment = path.segment()?;
             match segment.kind()? {
-                ast::PathSegmentKind::Name(name) => segments.push(name.text()),
+                ast::PathSegmentKind::Name(name) => segments.push(name.as_name()),
                 ast::PathSegmentKind::CrateKw => {
                     kind = PathKind::Crate;
                     break;
@@ -67,6 +69,14 @@ impl Path {
     pub fn is_ident(&self) -> bool {
         self.kind == PathKind::Plain && self.segments.len() == 1
     }
+
+    /// 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 {
+            return None;
+        }
+        self.segments.first()
+    }
 }
 
 fn expand_use_tree(
@@ -130,7 +140,7 @@ fn convert_path(prefix: Option<Path>, path: ast::Path) -> Option<Path> {
                 kind: PathKind::Plain,
                 segments: Vec::with_capacity(1),
             });
-            res.segments.push(name.text());
+            res.segments.push(name.as_name());
             res
         }
         ast::PathSegmentKind::CrateKw => {
diff --git a/crates/ra_hir/src/query_definitions.rs b/crates/ra_hir/src/query_definitions.rs
index 4a7958a122..e6241342ac 100644
--- a/crates/ra_hir/src/query_definitions.rs
+++ b/crates/ra_hir/src/query_definitions.rs
@@ -11,7 +11,7 @@ use ra_syntax::{
 use ra_db::{SourceRootId, FileId, Cancelable,};
 
 use crate::{
-    SourceFileItems, SourceItemId, DefKind, Function, DefId,
+    SourceFileItems, SourceItemId, DefKind, Function, DefId, Name, AsName,
     db::HirDatabase,
     function::{FnScopes, FnId},
     module::{
@@ -130,14 +130,14 @@ pub(crate) fn submodules(
 
 pub(crate) fn modules<'a>(
     root: impl ast::ModuleItemOwner<'a>,
-) -> impl Iterator<Item = (SmolStr, ast::Module<'a>)> {
+) -> impl Iterator<Item = (Name, ast::Module<'a>)> {
     root.items()
         .filter_map(|item| match item {
             ast::ModuleItem::Module(m) => Some(m),
             _ => None,
         })
         .filter_map(|module| {
-            let name = module.name()?.text();
+            let name = module.name()?.as_name();
             Some((name, module))
         })
 }
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs
index a0165aef2d..a0d1daf711 100644
--- a/crates/ra_hir/src/source_binder.rs
+++ b/crates/ra_hir/src/source_binder.rs
@@ -8,14 +8,14 @@
 use ra_db::{FileId, FilePosition, Cancelable};
 use ra_editor::find_node_at_offset;
 use ra_syntax::{
-    ast::{self, AstNode},
+    ast::{self, AstNode, NameOwner},
     SyntaxNodeRef,
 };
 
 use crate::{
     HirDatabase, Module, Function, SourceItemId,
     module::ModuleSource,
-    DefKind, DefLoc
+    DefKind, DefLoc, AsName,
 };
 
 /// Locates the module by `FileId`. Picks topmost module in the file.
@@ -24,6 +24,25 @@ pub fn module_from_file_id(db: &impl HirDatabase, file_id: FileId) -> Cancelable
     module_from_source(db, module_source)
 }
 
+/// Locates the child module by `mod child;` declaration.
+pub fn module_from_declaration(
+    db: &impl HirDatabase,
+    file_id: FileId,
+    decl: ast::Module,
+) -> Cancelable<Option<Module>> {
+    let parent_module = module_from_file_id(db, file_id)?;
+    let child_name = decl.name();
+    match (parent_module, child_name) {
+        (Some(parent_module), Some(child_name)) => {
+            if let Some(child) = parent_module.child(&child_name.as_name()) {
+                return Ok(Some(child));
+            }
+        }
+        _ => (),
+    }
+    Ok(None)
+}
+
 /// Locates the module by position in the source code.
 pub fn module_from_position(
     db: &impl HirDatabase,
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs
index 67b523c2cc..ad097d1f13 100644
--- a/crates/ra_hir/src/ty.rs
+++ b/crates/ra_hir/src/ty.rs
@@ -95,7 +95,7 @@ pub enum Ty {
     Tuple(Vec<Ty>),
 
     // The projection of an associated type.  For example,
-    // `<T as Trait<..>>::N`.
+    // `<T as Trait<..>>::N`.pub
     // Projection(ProjectionTy),
 
     // Opaque (`impl Trait`) type found in a return type.
@@ -179,13 +179,12 @@ impl Ty {
         module: &Module,
         path: &Path,
     ) -> Cancelable<Self> {
-        if path.is_ident() {
-            let name = &path.segments[0];
-            if let Some(int_ty) = primitive::IntTy::from_string(&name) {
+        if let Some(name) = path.as_ident() {
+            if let Some(int_ty) = primitive::IntTy::from_name(name) {
                 return Ok(Ty::Int(int_ty));
-            } else if let Some(uint_ty) = primitive::UintTy::from_string(&name) {
+            } else if let Some(uint_ty) = primitive::UintTy::from_name(name) {
                 return Ok(Ty::Uint(uint_ty));
-            } else if let Some(float_ty) = primitive::FloatTy::from_string(&name) {
+            } else if let Some(float_ty) = primitive::FloatTy::from_name(name) {
                 return Ok(Ty::Float(float_ty));
             }
         }
diff --git a/crates/ra_hir/src/ty/primitive.rs b/crates/ra_hir/src/ty/primitive.rs
index ad79b17e41..498d42d52e 100644
--- a/crates/ra_hir/src/ty/primitive.rs
+++ b/crates/ra_hir/src/ty/primitive.rs
@@ -1,5 +1,7 @@
 use std::fmt;
 
+use crate::{Name, KnownName};
+
 #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy)]
 pub enum IntTy {
     Isize,
@@ -34,14 +36,14 @@ impl IntTy {
         }
     }
 
-    pub fn from_string(s: &str) -> Option<IntTy> {
-        match s {
-            "isize" => Some(IntTy::Isize),
-            "i8" => Some(IntTy::I8),
-            "i16" => Some(IntTy::I16),
-            "i32" => Some(IntTy::I32),
-            "i64" => Some(IntTy::I64),
-            "i128" => Some(IntTy::I128),
+    pub fn from_name(name: &Name) -> Option<IntTy> {
+        match name.as_known_name()? {
+            KnownName::Isize => Some(IntTy::Isize),
+            KnownName::I8 => Some(IntTy::I8),
+            KnownName::I16 => Some(IntTy::I16),
+            KnownName::I32 => Some(IntTy::I32),
+            KnownName::I64 => Some(IntTy::I64),
+            KnownName::I128 => Some(IntTy::I128),
             _ => None,
         }
     }
@@ -69,14 +71,14 @@ impl UintTy {
         }
     }
 
-    pub fn from_string(s: &str) -> Option<UintTy> {
-        match s {
-            "usize" => Some(UintTy::Usize),
-            "u8" => Some(UintTy::U8),
-            "u16" => Some(UintTy::U16),
-            "u32" => Some(UintTy::U32),
-            "u64" => Some(UintTy::U64),
-            "u128" => Some(UintTy::U128),
+    pub fn from_name(name: &Name) -> Option<UintTy> {
+        match name.as_known_name()? {
+            KnownName::Usize => Some(UintTy::Usize),
+            KnownName::U8 => Some(UintTy::U8),
+            KnownName::U16 => Some(UintTy::U16),
+            KnownName::U32 => Some(UintTy::U32),
+            KnownName::U64 => Some(UintTy::U64),
+            KnownName::U128 => Some(UintTy::U128),
             _ => None,
         }
     }
@@ -120,10 +122,10 @@ impl FloatTy {
         }
     }
 
-    pub fn from_string(s: &str) -> Option<FloatTy> {
-        match s {
-            "f32" => Some(FloatTy::F32),
-            "f64" => Some(FloatTy::F64),
+    pub fn from_name(name: &Name) -> Option<FloatTy> {
+        match name.as_known_name()? {
+            KnownName::F32 => Some(FloatTy::F32),
+            KnownName::F64 => Some(FloatTy::F64),
             _ => None,
         }
     }
diff --git a/editors/README.md b/editors/README.md
index ad2ce16954..a39ec62b0a 100644
--- a/editors/README.md
+++ b/editors/README.md
@@ -1,8 +1,6 @@
 To install experimental VS Code plugin:
 
 ```
-$ git clone https://github.com/rust-analyzer/rust-analyzer.git
-$ cd rust-analyzer
 $ cargo install-code
 ```
 


Test patch:
diff --git a/crates/ra_hir/src/module/nameres/tests.rs b/crates/ra_hir/src/module/nameres/tests.rs
index 03ea5c1d6c..ca20f064f1 100644
--- a/crates/ra_hir/src/module/nameres/tests.rs
+++ b/crates/ra_hir/src/module/nameres/tests.rs
@@ -2,8 +2,8 @@ use std::sync::Arc;
 
 use salsa::Database;
 use ra_db::{FilesDatabase, CrateGraph};
-use ra_syntax::SmolStr;
 use relative_path::RelativePath;
+use test_utils::assert_eq_text;
 
 use crate::{
     self as hir,
@@ -21,6 +21,35 @@ fn item_map(fixture: &str) -> (Arc<hir::ItemMap>, hir::ModuleId) {
     (db.item_map(source_root).unwrap(), module_id)
 }
 
+fn check_module_item_map(map: &hir::ItemMap, module_id: hir::ModuleId, expected: &str) {
+    let mut lines = map.per_module[&module_id]
+        .items
+        .iter()
+        .map(|(name, res)| format!("{}: {}", name, dump_resolution(res)))
+        .collect::<Vec<_>>();
+    lines.sort();
+    let actual = lines.join("\n");
+    let expected = expected
+        .trim()
+        .lines()
+        .map(|it| it.trim())
+        .collect::<Vec<_>>()
+        .join("\n");
+    assert_eq_text!(&actual, &expected);
+
+    fn dump_resolution(resolution: &hir::Resolution) -> &'static str {
+        match (
+            resolution.def_id.types.is_some(),
+            resolution.def_id.values.is_some(),
+        ) {
+            (true, true) => "t v",
+            (true, false) => "t",
+            (false, true) => "v",
+            (false, false) => "_",
+        }
+    }
+}
+
 #[test]
 fn item_map_smoke_test() {
     let (item_map, module_id) = item_map(
@@ -38,13 +67,18 @@ fn item_map_smoke_test() {
         pub struct Baz;
     ",
     );
-    let name = SmolStr::from("Baz");
-    let resolution = &item_map.per_module[&module_id].items[&name];
-    assert!(resolution.def_id.take_types().is_some());
+    check_module_item_map(
+        &item_map,
+        module_id,
+        "
+            Baz: t v
+            foo: t
+        ",
+    );
 }
 
 #[test]
-fn test_self() {
+fn item_map_using_self() {
     let (item_map, module_id) = item_map(
         "
             //- /lib.rs
@@ -57,9 +91,14 @@ fn test_self() {
             pub struct Baz;
         ",
     );
-    let name = SmolStr::from("Baz");
-    let resolution = &item_map.per_module[&module_id].items[&name];
-    assert!(resolution.def_id.take_types().is_some());
+    check_module_item_map(
+        &item_map,
+        module_id,
+        "
+            Baz: t v
+            foo: t
+        ",
+    );
 }
 
 #[test]
@@ -90,9 +129,14 @@ fn item_map_across_crates() {
     let module_id = module.module_id;
     let item_map = db.item_map(source_root).unwrap();
 
-    let name = SmolStr::from("Baz");
-    let resolution = &item_map.per_module[&module_id].items[&name];
-    assert!(resolution.def_id.take_types().is_some());
+    check_module_item_map(
+        &item_map,
+        module_id,
+        "
+            Baz: t v
+            test_crate: t
+        ",
+    );
 }
 
 #[test]