Repository: rust-analyzer/rust-analyzer
Pull request #11882 (2022-04-02 14:19:25)

internal: Record outline child modules with missing backing file in def map
bors r+


Patch:
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs
index 14b26bcf45..15e93f729a 100644
--- a/crates/hir_def/src/nameres/collector.rs
+++ b/crates/hir_def/src/nameres/collector.rs
@@ -1743,6 +1743,12 @@ impl ModCollector<'_, '_> {
                         }
                     }
                     Err(candidates) => {
+                        self.push_child_module(
+                            module.name.clone(),
+                            ast_id,
+                            None,
+                            &self.item_tree[module.visibility],
+                        );
                         self.def_collector.def_map.diagnostics.push(
                             DefDiagnostic::unresolved_module(self.module_id, ast_id, candidates),
                         );
diff --git a/crates/hir_ty/src/db.rs b/crates/hir_ty/src/db.rs
index de4c153590..467dcfa33e 100644
--- a/crates/hir_ty/src/db.rs
+++ b/crates/hir_ty/src/db.rs
@@ -3,7 +3,6 @@
 
 use std::sync::Arc;
 
-use arrayvec::ArrayVec;
 use base_db::{impl_intern_key, salsa, CrateId, Upcast};
 use hir_def::{
     db::DefDatabase, expr::ExprId, BlockId, ConstId, ConstParamId, DefWithBodyId, FunctionId,
@@ -14,7 +13,7 @@ use la_arena::ArenaMap;
 use crate::{
     chalk_db,
     consteval::{ComputedExpr, ConstEvalError},
-    method_resolution::{InherentImpls, TraitImpls, TyFingerprint},
+    method_resolution::{InherentImpls, TraitImpls},
     Binders, CallableDefId, FnDefId, GenericArg, ImplTraitId, InferenceResult, Interner, PolyFnSig,
     QuantifiedWhereClause, ReturnTypeImplTraits, TraitRef, Ty, TyDefId, ValueTyDefId,
 };
@@ -87,12 +86,6 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
     #[salsa::invoke(InherentImpls::inherent_impls_in_block_query)]
     fn inherent_impls_in_block(&self, block: BlockId) -> Option<Arc<InherentImpls>>;
 
-    /// Collects all crates in the dependency graph that have impls for the
-    /// given fingerprint. This is only used for primitive types; for
-    /// user-defined types we just look at the crate where the type is defined.
-    #[salsa::invoke(crate::method_resolution::inherent_impl_crates_query)]
-    fn inherent_impl_crates(&self, krate: CrateId, fp: TyFingerprint) -> ArrayVec<CrateId, 2>;
-
     #[salsa::invoke(TraitImpls::trait_impls_in_crate_query)]
     fn trait_impls_in_crate(&self, krate: CrateId) -> Arc<TraitImpls>;
 
diff --git a/crates/hir_ty/src/method_resolution.rs b/crates/hir_ty/src/method_resolution.rs
index d5285c1710..768772d5c3 100644
--- a/crates/hir_ty/src/method_resolution.rs
+++ b/crates/hir_ty/src/method_resolution.rs
@@ -8,8 +8,9 @@ use arrayvec::ArrayVec;
 use base_db::{CrateId, Edition};
 use chalk_ir::{cast::Cast, Mutability, UniverseIndex};
 use hir_def::{
-    item_scope::ItemScope, nameres::DefMap, AssocItemId, BlockId, ConstId, FunctionId,
-    GenericDefId, HasModule, ImplId, ItemContainerId, Lookup, ModuleDefId, ModuleId, TraitId,
+    item_scope::ItemScope, lang_item::LangItemTarget, nameres::DefMap, AssocItemId, BlockId,
+    ConstId, FunctionId, GenericDefId, HasModule, ImplId, ItemContainerId, Lookup, ModuleDefId,
+    ModuleId, TraitId,
 };
 use hir_expand::name::Name;
 use rustc_hash::{FxHashMap, FxHashSet};
@@ -20,7 +21,7 @@ use crate::{
     db::HirDatabase,
     from_foreign_def_id,
     infer::{unify::InferenceTable, Adjust, Adjustment, AutoBorrow, OverloadedDeref, PointerCast},
-    primitive::{FloatTy, IntTy, UintTy},
+    primitive::{self, FloatTy, IntTy, UintTy},
     static_lifetime,
     utils::all_super_traits,
     AdtId, Canonical, CanonicalVarKinds, DebruijnIndex, ForeignDefId, InEnvironment, Interner,
@@ -336,30 +337,6 @@ impl InherentImpls {
     }
 }
 
-pub fn inherent_impl_crates_query(
-    db: &dyn HirDatabase,
-    krate: CrateId,
-    fp: TyFingerprint,
-) -> ArrayVec<CrateId, 2> {
-    let _p = profile::span("inherent_impl_crates_query");
-    let mut res = ArrayVec::new();
-    let crate_graph = db.crate_graph();
-
-    for krate in crate_graph.transitive_deps(krate) {
-        if res.is_full() {
-            // we don't currently look for or store more than two crates here,
-            // so don't needlessly look at more crates than necessary.
-            break;
-        }
-        let impls = db.inherent_impls_in_crate(krate);
-        if impls.map.get(&fp).map_or(false, |v| !v.is_empty()) {
-            res.push(krate);
-        }
-    }
-
-    res
-}
-
 fn collect_unnamed_consts<'a>(
     db: &'a dyn HirDatabase,
     scope: &'a ItemScope,
@@ -393,30 +370,63 @@ pub fn def_crates(
     ty: &Ty,
     cur_crate: CrateId,
 ) -> Option<ArrayVec<CrateId, 2>> {
-    let mod_to_crate_ids = |module: ModuleId| Some(iter::once(module.krate()).collect());
+    // Types like slice can have inherent impls in several crates, (core and alloc).
+    // The corresponding impls are marked with lang items, so we can use them to find the required crates.
+    macro_rules! lang_item_crate {
+            ($($name:expr),+ $(,)?) => {{
+                let mut v = ArrayVec::<LangItemTarget, 2>::new();
+                $(
+                    v.extend(db.lang_item(cur_crate, $name.into()));
+                )+
+                v
+            }};
+        }
 
-    let fp = TyFingerprint::for_inherent_impl(ty);
+    let mod_to_crate_ids = |module: ModuleId| Some(iter::once(module.krate()).collect());
 
-    match ty.kind(Interner) {
-        TyKind::Adt(AdtId(def_id), _) => mod_to_crate_ids(def_id.module(db.upcast())),
+    let lang_item_targets = match ty.kind(Interner) {
+        TyKind::Adt(AdtId(def_id), _) => {
+            return mod_to_crate_ids(def_id.module(db.upcast()));
+        }
         TyKind::Foreign(id) => {
-            mod_to_crate_ids(from_foreign_def_id(*id).lookup(db.upcast()).module(db.upcast()))
+            return mod_to_crate_ids(
+                from_foreign_def_id(*id).lookup(db.upcast()).module(db.upcast()),
+            );
+        }
+        TyKind::Scalar(Scalar::Bool) => lang_item_crate!("bool"),
+        TyKind::Scalar(Scalar::Char) => lang_item_crate!("char"),
+        TyKind::Scalar(Scalar::Float(f)) => match f {
+            // There are two lang items: one in libcore (fXX) and one in libstd (fXX_runtime)
+            FloatTy::F32 => lang_item_crate!("f32", "f32_runtime"),
+            FloatTy::F64 => lang_item_crate!("f64", "f64_runtime"),
+        },
+        &TyKind::Scalar(Scalar::Int(t)) => {
+            lang_item_crate!(primitive::int_ty_to_string(t))
         }
-        TyKind::Dyn(_) => ty
-            .dyn_trait()
-            .and_then(|trait_| mod_to_crate_ids(GenericDefId::TraitId(trait_).module(db.upcast()))),
-        // for primitives, there may be impls in various places (core and alloc
-        // mostly). We just check the whole crate graph for crates with impls
-        // (cached behind a query).
-        TyKind::Scalar(_)
-        | TyKind::Str
-        | TyKind::Slice(_)
-        | TyKind::Array(..)
-        | TyKind::Raw(..) => {
-            Some(db.inherent_impl_crates(cur_crate, fp.expect("fingerprint for primitive")))
+        &TyKind::Scalar(Scalar::Uint(t)) => {
+            lang_item_crate!(primitive::uint_ty_to_string(t))
+        }
+        TyKind::Str => lang_item_crate!("str_alloc", "str"),
+        TyKind::Slice(_) => lang_item_crate!("slice_alloc", "slice"),
+        TyKind::Array(..) => lang_item_crate!("array"),
+        TyKind::Raw(Mutability::Not, _) => lang_item_crate!("const_ptr"),
+        TyKind::Raw(Mutability::Mut, _) => lang_item_crate!("mut_ptr"),
+        TyKind::Dyn(_) => {
+            return ty.dyn_trait().and_then(|trait_| {
+                mod_to_crate_ids(GenericDefId::TraitId(trait_).module(db.upcast()))
+            });
         }
         _ => return None,
-    }
+    };
+    let res = lang_item_targets
+        .into_iter()
+        .filter_map(|it| match it {
+            LangItemTarget::ImplDefId(it) => Some(it),
+            _ => None,
+        })
+        .map(|it| it.lookup(db.upcast()).container.krate())
+        .collect();
+    Some(res)
 }
 
 /// Look up the method with the given name.
diff --git a/crates/hir_ty/src/utils.rs b/crates/hir_ty/src/utils.rs
index c4a11c86d4..343e89eb9b 100644
--- a/crates/hir_ty/src/utils.rs
+++ b/crates/hir_ty/src/utils.rs
@@ -175,15 +175,6 @@ pub(super) fn associated_type_by_name_including_super_traits(
 
 pub(crate) fn generics(db: &dyn DefDatabase, def: GenericDefId) -> Generics {
     let parent_generics = parent_generic_def(db, def).map(|def| Box::new(generics(db, def)));
-    if parent_generics.is_some() && matches!(def, GenericDefId::TypeAliasId(_)) {
-        // XXX: treat generic associated types as not existing to avoid crashes (#)
-        //
-        // Chalk expects the inner associated type's parameters to come
-        // *before*, not after the trait's generics as we've always done it.
-        // Adapting to this requires a larger refactoring
-        cov_mark::hit!(ignore_gats);
-        return Generics { def, params: Interned::new(Default::default()), parent_generics };
-    }
     Generics { def, params: db.generic_params(def), parent_generics }
 }
 


Test patch:
diff --git a/crates/hir_def/src/nameres/tests.rs b/crates/hir_def/src/nameres/tests.rs
index 4794932855..80e5476071 100644
--- a/crates/hir_def/src/nameres/tests.rs
+++ b/crates/hir_def/src/nameres/tests.rs
@@ -375,9 +375,12 @@ pub struct Arc;
 "#,
         expect![[r#"
             crate
+            alloc: t
             alloc_crate: t
             sync: t
 
+            crate::alloc
+
             crate::sync
             Arc: t v
         "#]],
@@ -401,9 +404,12 @@ pub struct Arc;
 "#,
         expect![[r#"
             crate
+            alloc: t
             alloc_crate: t
             sync: t
 
+            crate::alloc
+
             crate::sync
             Arc: t v
         "#]],
diff --git a/crates/hir_def/src/nameres/tests/mod_resolution.rs b/crates/hir_def/src/nameres/tests/mod_resolution.rs
index 16a2cd27af..79a74873b4 100644
--- a/crates/hir_def/src/nameres/tests/mod_resolution.rs
+++ b/crates/hir_def/src/nameres/tests/mod_resolution.rs
@@ -526,6 +526,9 @@ pub struct Baz;
 "#,
         expect![[r#"
             crate
+            foo: t
+
+            crate::foo
         "#]],
     );
 }
diff --git a/crates/hir_ty/src/tests/method_resolution.rs b/crates/hir_ty/src/tests/method_resolution.rs
index d97147541a..011347e5c4 100644
--- a/crates/hir_ty/src/tests/method_resolution.rs
+++ b/crates/hir_ty/src/tests/method_resolution.rs
@@ -6,39 +6,33 @@ use super::{check_infer, check_no_mismatches, check_types};
 
 #[test]
 fn infer_slice_method() {
-    check_types(
+    check_infer(
         r#"
-impl<T> [T] {
-    fn foo(&self) -> T {
-        loop {}
-    }
-}
-
-fn test(x: &[u8]) {
-    <[_]>::foo(x);
-  //^^^^^^^^^^^^^ u8
-}
-        "#,
-    );
-}
+        #[lang = "slice"]
+        impl<T> [T] {
+            fn foo(&self) -> T {
+                loop {}
+            }
+        }
 
-#[test]
-fn cross_crate_primitive_method() {
-    check_types(
-        r#"
-//- /main.rs crate:main deps:other_crate
-fn test() {
-    let x = 1f32;
-    x.foo();
-} //^^^^^^^ f32
+        #[lang = "slice_alloc"]
+        impl<T> [T] {}
 
-//- /lib.rs crate:other_crate
-mod foo {
-    impl f32 {
-        pub fn foo(self) -> f32 { 0. }
-    }
-}
-"#,
+        fn test(x: &[u8]) {
+            <[_]>::foo(x);
+        }
+        "#,
+        expect![[r#"
+            44..48 'self': &[T]
+            55..78 '{     ...     }': T
+            65..72 'loop {}': !
+            70..72 '{}': ()
+            130..131 'x': &[u8]
+            140..162 '{     ...(x); }': ()
+            146..156 '<[_]>::foo': fn foo<u8>(&[u8]) -> u8
+            146..159 '<[_]>::foo(x)': u8
+            157..158 'x': &[u8]
+        "#]],
     );
 }
 
@@ -46,15 +40,16 @@ mod foo {
 fn infer_array_inherent_impl() {
     check_types(
         r#"
-impl<T, const N: usize> [T; N] {
-    fn foo(&self) -> T {
-        loop {}
-    }
-}
-fn test(x: &[u8; 0]) {
-    <[_; 0]>::foo(x);
-  //^^^^^^^^^^^^^^^^ u8
-}
+        #[lang = "array"]
+        impl<T, const N: usize> [T; N] {
+            fn foo(&self) -> T {
+                loop {}
+            }
+        }
+        fn test(x: &[u8; 0]) {
+            <[_; 0]>::foo(x);
+          //^^^^^^^^^^^^^^^^ u8
+        }
         "#,
     );
 }
diff --git a/crates/hir_ty/src/tests/regression.rs b/crates/hir_ty/src/tests/regression.rs
index 65eb2da5af..2809b1e912 100644
--- a/crates/hir_ty/src/tests/regression.rs
+++ b/crates/hir_ty/src/tests/regression.rs
@@ -1497,22 +1497,3 @@ fn regression_11688_3() {
         "#,
     );
 }
-
-#[test]
-fn gat_crash() {
-    cov_mark::check!(ignore_gats);
-    check_no_mismatches(
-        r#"
-trait ATrait {}
-
-trait Crash {
-    type Member<const N: usize>: ATrait;
-    fn new<const N: usize>() -> Self::Member<N>;
-}
-
-fn test<T: Crash>() {
-    T::new();
-}
-"#,
-    );
-}