From d963042ca9da93be8d5922ce46ea26dc6a79c929 Mon Sep 17 00:00:00 2001
From: Aleksey Kladov <aleksey.kladov@gmail.com>
Date: Thu, 27 Dec 2018 20:07:21 +0300
Subject: introduce hir::Name

---
 crates/ra_hir/src/krate.rs                |  7 ++--
 crates/ra_hir/src/lib.rs                  |  3 ++
 crates/ra_hir/src/module.rs               | 19 ++++++-----
 crates/ra_hir/src/module/imp.rs           | 19 +++++------
 crates/ra_hir/src/module/nameres.rs       | 25 ++++++++------
 crates/ra_hir/src/module/nameres/tests.rs |  7 ++--
 crates/ra_hir/src/name.rs                 | 56 +++++++++++++++++++++++++++++++
 crates/ra_hir/src/path.rs                 | 18 +++++++---
 crates/ra_hir/src/query_definitions.rs    |  6 ++--
 crates/ra_hir/src/ty.rs                   | 10 +++---
 10 files changed, 120 insertions(+), 50 deletions(-)
 create mode 100644 crates/ra_hir/src/name.rs

(limited to 'crates/ra_hir')

diff --git a/crates/ra_hir/src/krate.rs b/crates/ra_hir/src/krate.rs
index 1196dcef1..89b1e639e 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 f1cc0ccd0..bf43cd0ae 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,
 };
 
 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 b9d36f01f..43413acb8 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 748fdb64e..eded85a63 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 98cd225dd..68eb02a98 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/module/nameres/tests.rs b/crates/ra_hir/src/module/nameres/tests.rs
index 03ea5c1d6..165ac81c8 100644
--- a/crates/ra_hir/src/module/nameres/tests.rs
+++ b/crates/ra_hir/src/module/nameres/tests.rs
@@ -9,6 +9,7 @@ use crate::{
     self as hir,
     db::HirDatabase,
     mock::MockDatabase,
+    Name,
 };
 
 fn item_map(fixture: &str) -> (Arc<hir::ItemMap>, hir::ModuleId) {
@@ -38,7 +39,7 @@ fn item_map_smoke_test() {
         pub struct Baz;
     ",
     );
-    let name = SmolStr::from("Baz");
+    let name = Name::new(SmolStr::from("Baz"));
     let resolution = &item_map.per_module[&module_id].items[&name];
     assert!(resolution.def_id.take_types().is_some());
 }
@@ -57,7 +58,7 @@ fn test_self() {
             pub struct Baz;
         ",
     );
-    let name = SmolStr::from("Baz");
+    let name = Name::new(SmolStr::from("Baz"));
     let resolution = &item_map.per_module[&module_id].items[&name];
     assert!(resolution.def_id.take_types().is_some());
 }
@@ -90,7 +91,7 @@ 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 name = Name::new(SmolStr::from("Baz"));
     let resolution = &item_map.per_module[&module_id].items[&name];
     assert!(resolution.def_id.take_types().is_some());
 }
diff --git a/crates/ra_hir/src/name.rs b/crates/ra_hir/src/name.rs
new file mode 100644
index 000000000..7f42c9f04
--- /dev/null
+++ b/crates/ra_hir/src/name.rs
@@ -0,0 +1,56 @@
+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(Debug, 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 Name {
+    // TODO: get rid of this?
+    pub(crate) fn as_str(&self) -> &str {
+        self.text.as_str()
+    }
+
+    #[cfg(not(test))]
+    fn new(text: SmolStr) -> Name {
+        Name { text }
+    }
+
+    #[cfg(test)]
+    pub(crate) 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())
+    }
+}
diff --git a/crates/ra_hir/src/path.rs b/crates/ra_hir/src/path.rs
index 0b260072c..93f7203fe 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 4a7958a12..e6241342a 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/ty.rs b/crates/ra_hir/src/ty.rs
index 67b523c2c..dc3323b1a 100644
--- a/crates/ra_hir/src/ty.rs
+++ b/crates/ra_hir/src/ty.rs
@@ -179,13 +179,13 @@ 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() {
+            let name = name.as_str(); // :-(
+            if let Some(int_ty) = primitive::IntTy::from_string(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_string(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_string(name) {
                 return Ok(Ty::Float(float_ty));
             }
         }
-- 
cgit v1.2.3


From a9f55029b9db3bcd439d31c5007785299f7d4025 Mon Sep 17 00:00:00 2001
From: Aleksey Kladov <aleksey.kladov@gmail.com>
Date: Thu, 27 Dec 2018 20:26:15 +0300
Subject: introduce known names

---
 crates/ra_hir/src/lib.rs          |  2 +-
 crates/ra_hir/src/name.rs         | 47 ++++++++++++++++++++++++++++++++++++---
 crates/ra_hir/src/ty.rs           |  9 ++++----
 crates/ra_hir/src/ty/primitive.rs | 42 +++++++++++++++++-----------------
 4 files changed, 71 insertions(+), 29 deletions(-)

(limited to 'crates/ra_hir')

diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs
index bf43cd0ae..5bbb09c01 100644
--- a/crates/ra_hir/src/lib.rs
+++ b/crates/ra_hir/src/lib.rs
@@ -38,7 +38,7 @@ use ra_db::{LocationIntener, SourceRootId, FileId, Cancelable};
 use crate::{
     db::HirDatabase,
     arena::{Arena, Id},
-    name::AsName,
+    name::{AsName, KnownName},
 };
 
 pub use self::{
diff --git a/crates/ra_hir/src/name.rs b/crates/ra_hir/src/name.rs
index 7f42c9f04..cdad31be7 100644
--- a/crates/ra_hir/src/name.rs
+++ b/crates/ra_hir/src/name.rs
@@ -17,9 +17,25 @@ impl fmt::Display for Name {
 }
 
 impl Name {
-    // TODO: get rid of this?
-    pub(crate) fn as_str(&self) -> &str {
-        self.text.as_str()
+    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)
     }
 
     #[cfg(not(test))]
@@ -54,3 +70,28 @@ impl AsName for ra_db::Dependency {
         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/ty.rs b/crates/ra_hir/src/ty.rs
index dc3323b1a..ad097d1f1 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.
@@ -180,12 +180,11 @@ impl Ty {
         path: &Path,
     ) -> Cancelable<Self> {
         if let Some(name) = path.as_ident() {
-            let name = name.as_str(); // :-(
-            if let Some(int_ty) = primitive::IntTy::from_string(name) {
+            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 ad79b17e4..498d42d52 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,
         }
     }
-- 
cgit v1.2.3


From 63f54d234f0d622d043dca8176f0715889a6ed48 Mon Sep 17 00:00:00 2001
From: Aleksey Kladov <aleksey.kladov@gmail.com>
Date: Thu, 27 Dec 2018 21:02:08 +0300
Subject: dont leak Name details in testing

---
 crates/ra_hir/src/module/nameres/tests.rs | 67 +++++++++++++++++++++++++------
 crates/ra_hir/src/name.rs                 | 14 +++----
 2 files changed, 62 insertions(+), 19 deletions(-)

(limited to 'crates/ra_hir')

diff --git a/crates/ra_hir/src/module/nameres/tests.rs b/crates/ra_hir/src/module/nameres/tests.rs
index 165ac81c8..ca20f064f 100644
--- a/crates/ra_hir/src/module/nameres/tests.rs
+++ b/crates/ra_hir/src/module/nameres/tests.rs
@@ -2,14 +2,13 @@ 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,
     db::HirDatabase,
     mock::MockDatabase,
-    Name,
 };
 
 fn item_map(fixture: &str) -> (Arc<hir::ItemMap>, hir::ModuleId) {
@@ -22,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(
@@ -39,13 +67,18 @@ fn item_map_smoke_test() {
         pub struct Baz;
     ",
     );
-    let name = Name::new(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
@@ -58,9 +91,14 @@ fn test_self() {
             pub struct Baz;
         ",
     );
-    let name = Name::new(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]
@@ -91,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 = Name::new(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]
diff --git a/crates/ra_hir/src/name.rs b/crates/ra_hir/src/name.rs
index cdad31be7..e4fc141a6 100644
--- a/crates/ra_hir/src/name.rs
+++ b/crates/ra_hir/src/name.rs
@@ -5,7 +5,7 @@ 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(Debug, Clone, PartialEq, Eq, Hash)]
+#[derive(Clone, PartialEq, Eq, Hash)]
 pub struct Name {
     text: SmolStr,
 }
@@ -16,6 +16,12 @@ impl fmt::Display for Name {
     }
 }
 
+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() {
@@ -38,15 +44,9 @@ impl Name {
         Some(name)
     }
 
-    #[cfg(not(test))]
     fn new(text: SmolStr) -> Name {
         Name { text }
     }
-
-    #[cfg(test)]
-    pub(crate) fn new(text: SmolStr) -> Name {
-        Name { text }
-    }
 }
 
 pub(crate) trait AsName {
-- 
cgit v1.2.3


From e0660506719476a0546e10bee816d7220be85440 Mon Sep 17 00:00:00 2001
From: Aleksey Kladov <aleksey.kladov@gmail.com>
Date: Thu, 27 Dec 2018 21:21:10 +0300
Subject: use names everywhere

---
 crates/ra_hir/src/function/scope.rs | 24 ++++++++++++++----------
 crates/ra_hir/src/source_binder.rs  | 23 +++++++++++++++++++++--
 2 files changed, 35 insertions(+), 12 deletions(-)

(limited to 'crates/ra_hir')

diff --git a/crates/ra_hir/src/function/scope.rs b/crates/ra_hir/src/function/scope.rs
index a1a580979..3e4cfad0c 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/source_binder.rs b/crates/ra_hir/src/source_binder.rs
index a0165aef2..a0d1daf71 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,
-- 
cgit v1.2.3