Repository: rust-analyzer/rust-analyzer
Pull request #8075 (2021-03-17 21:25:11)

Fix `use crate as <name>;` imports
Fixes https://github.com/rust-analyzer/rust-analyzer/issues/4644

bors r+


Patch:
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs
index d73f895b7d..b5ae5a9e44 100644
--- a/crates/hir_def/src/nameres/collector.rs
+++ b/crates/hir_def/src/nameres/collector.rs
@@ -656,26 +656,28 @@ impl DefCollector<'_> {
                 }
             }
         } else {
-            match import.path.segments().last() {
-                Some(last_segment) => {
-                    let name = match &import.alias {
-                        Some(ImportAlias::Alias(name)) => Some(name.clone()),
-                        Some(ImportAlias::Underscore) => None,
-                        None => Some(last_segment.clone()),
-                    };
-                    log::debug!("resolved import {:?} ({:?}) to {:?}", name, import, def);
-
-                    // extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658
-                    if import.is_extern_crate && module_id == self.def_map.root {
-                        if let (Some(def), Some(name)) = (def.take_types(), name.as_ref()) {
-                            self.def_map.extern_prelude.insert(name.clone(), def);
-                        }
+            let name = match &import.alias {
+                Some(ImportAlias::Alias(name)) => Some(name.clone()),
+                Some(ImportAlias::Underscore) => None,
+                None => match import.path.segments().last() {
+                    Some(last_segment) => Some(last_segment.clone()),
+                    None => {
+                        cov_mark::hit!(bogus_paths);
+                        return;
                     }
+                },
+            };
+
+            log::debug!("resolved import {:?} ({:?}) to {:?}", name, import, def);
 
-                    self.update(module_id, &[(name, def)], vis, ImportType::Named);
+            // extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658
+            if import.is_extern_crate && module_id == self.def_map.root {
+                if let (Some(def), Some(name)) = (def.take_types(), name.as_ref()) {
+                    self.def_map.extern_prelude.insert(name.clone(), def);
                 }
-                None => cov_mark::hit!(bogus_paths),
             }
+
+            self.update(module_id, &[(name, def)], vis, ImportType::Named);
         }
     }
 
diff --git a/crates/hir_expand/src/builtin_macro.rs b/crates/hir_expand/src/builtin_macro.rs
index fce09a9e71..2a79c892b5 100644
--- a/crates/hir_expand/src/builtin_macro.rs
+++ b/crates/hir_expand/src/builtin_macro.rs
@@ -333,19 +333,17 @@ fn concat_expand(
 fn relative_file(
     db: &dyn AstDatabase,
     call_id: MacroCallId,
-    path_str: &str,
+    path: &str,
     allow_recursion: bool,
-) -> Result<FileId, mbe::ExpandError> {
+) -> Option<FileId> {
     let call_site = call_id.as_file().original_file(db);
-    let path = AnchoredPath { anchor: call_site, path: path_str };
-    let res = db
-        .resolve_path(path)
-        .ok_or_else(|| mbe::ExpandError::Other(format!("failed to load file `{}`", path_str)))?;
+    let path = AnchoredPath { anchor: call_site, path };
+    let res = db.resolve_path(path)?;
     // Prevent include itself
     if res == call_site && !allow_recursion {
-        Err(mbe::ExpandError::Other(format!("recursive inclusion of `{}`", path_str)))
+        None
     } else {
-        Ok(res)
+        Some(res)
     }
 }
 
@@ -366,7 +364,8 @@ fn include_expand(
 ) -> ExpandResult<Option<(tt::Subtree, FragmentKind)>> {
     let res = (|| {
         let path = parse_string(tt)?;
-        let file_id = relative_file(db, arg_id.into(), &path, false)?;
+        let file_id = relative_file(db, arg_id.into(), &path, false)
+            .ok_or_else(|| mbe::ExpandError::ConversionError)?;
 
         Ok(parse_to_token_tree(&db.file_text(file_id))
             .ok_or_else(|| mbe::ExpandError::ConversionError)?
@@ -418,8 +417,8 @@ fn include_str_expand(
     // Ideally, we'd be able to offer a precise expansion if the user asks for macro
     // expansion.
     let file_id = match relative_file(db, arg_id.into(), &path, true) {
-        Ok(file_id) => file_id,
-        Err(_) => {
+        Some(file_id) => file_id,
+        None => {
             return ExpandResult::ok(Some((quote!(""), FragmentKind::Expr)));
         }
     };


Test patch:
diff --git a/crates/hir_def/src/body/tests.rs b/crates/hir_def/src/body/tests.rs
index faa1332970..f8e6f70e87 100644
--- a/crates/hir_def/src/body/tests.rs
+++ b/crates/hir_def/src/body/tests.rs
@@ -137,7 +137,7 @@ fn f() {
     include!(invalid);
   //^^^^^^^^^^^^^^^^^ could not convert tokens
     include!("does not exist");
-  //^^^^^^^^^^^^^^^^^^^^^^^^^^ failed to load file `does not exist`
+  //^^^^^^^^^^^^^^^^^^^^^^^^^^ could not convert tokens
 
     env!(invalid);
   //^^^^^^^^^^^^^ could not convert tokens
diff --git a/crates/hir_def/src/nameres/tests.rs b/crates/hir_def/src/nameres/tests.rs
index de3aa4f9ae..4f2e7a2f96 100644
--- a/crates/hir_def/src/nameres/tests.rs
+++ b/crates/hir_def/src/nameres/tests.rs
@@ -713,3 +713,22 @@ pub fn f() {}
         "#]],
     );
 }
+
+#[test]
+fn use_crate_as() {
+    check(
+        r#"
+use crate as foo;
+
+use foo::bar as baz;
+
+fn bar() {}
+        "#,
+        expect![[r#"
+            crate
+            bar: v
+            baz: v
+            foo: t
+        "#]],
+    );
+}
diff --git a/crates/hir_def/src/nameres/tests/diagnostics.rs b/crates/hir_def/src/nameres/tests/diagnostics.rs
index a89061c2e8..6becd9ff1e 100644
--- a/crates/hir_def/src/nameres/tests/diagnostics.rs
+++ b/crates/hir_def/src/nameres/tests/diagnostics.rs
@@ -196,7 +196,7 @@ fn builtin_macro_fails_expansion() {
           macro_rules! include { () => {} }
 
           include!("doesntexist");
-        //^^^^^^^^^^^^^^^^^^^^^^^^ failed to load file `doesntexist`
+        //^^^^^^^^^^^^^^^^^^^^^^^^ could not convert tokens
         "#,
     );
 }