Unnamed repository; edit this file 'description' to name the repository.
-rw-r--r--crates/hir_ty/src/db.rs9
-rw-r--r--crates/hir_ty/src/method_resolution.rs100
-rw-r--r--crates/hir_ty/src/tests/method_resolution.rs73
3 files changed, 92 insertions, 90 deletions
diff --git a/crates/hir_ty/src/db.rs b/crates/hir_ty/src/db.rs
index 467dcfa33e..de4c153590 100644
--- a/crates/hir_ty/src/db.rs
+++ b/crates/hir_ty/src/db.rs
@@ -3,6 +3,7 @@
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,
@@ -13,7 +14,7 @@ use la_arena::ArenaMap;
use crate::{
chalk_db,
consteval::{ComputedExpr, ConstEvalError},
- method_resolution::{InherentImpls, TraitImpls},
+ method_resolution::{InherentImpls, TraitImpls, TyFingerprint},
Binders, CallableDefId, FnDefId, GenericArg, ImplTraitId, InferenceResult, Interner, PolyFnSig,
QuantifiedWhereClause, ReturnTypeImplTraits, TraitRef, Ty, TyDefId, ValueTyDefId,
};
@@ -86,6 +87,12 @@ 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 768772d5c3..d5285c1710 100644
--- a/crates/hir_ty/src/method_resolution.rs
+++ b/crates/hir_ty/src/method_resolution.rs
@@ -8,9 +8,8 @@ use arrayvec::ArrayVec;
use base_db::{CrateId, Edition};
use chalk_ir::{cast::Cast, Mutability, UniverseIndex};
use hir_def::{
- item_scope::ItemScope, lang_item::LangItemTarget, nameres::DefMap, AssocItemId, BlockId,
- ConstId, FunctionId, GenericDefId, HasModule, ImplId, ItemContainerId, Lookup, ModuleDefId,
- ModuleId, TraitId,
+ item_scope::ItemScope, nameres::DefMap, AssocItemId, BlockId, ConstId, FunctionId,
+ GenericDefId, HasModule, ImplId, ItemContainerId, Lookup, ModuleDefId, ModuleId, TraitId,
};
use hir_expand::name::Name;
use rustc_hash::{FxHashMap, FxHashSet};
@@ -21,7 +20,7 @@ use crate::{
db::HirDatabase,
from_foreign_def_id,
infer::{unify::InferenceTable, Adjust, Adjustment, AutoBorrow, OverloadedDeref, PointerCast},
- primitive::{self, FloatTy, IntTy, UintTy},
+ primitive::{FloatTy, IntTy, UintTy},
static_lifetime,
utils::all_super_traits,
AdtId, Canonical, CanonicalVarKinds, DebruijnIndex, ForeignDefId, InEnvironment, Interner,
@@ -337,6 +336,30 @@ 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,
@@ -370,63 +393,30 @@ pub fn def_crates(
ty: &Ty,
cur_crate: CrateId,
) -> Option<ArrayVec<CrateId, 2>> {
- // 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 mod_to_crate_ids = |module: ModuleId| Some(iter::once(module.krate()).collect());
- let lang_item_targets = match ty.kind(Interner) {
- TyKind::Adt(AdtId(def_id), _) => {
- return mod_to_crate_ids(def_id.module(db.upcast()));
- }
+ let fp = TyFingerprint::for_inherent_impl(ty);
+
+ match ty.kind(Interner) {
+ TyKind::Adt(AdtId(def_id), _) => mod_to_crate_ids(def_id.module(db.upcast())),
TyKind::Foreign(id) => {
- 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))
+ mod_to_crate_ids(from_foreign_def_id(*id).lookup(db.upcast()).module(db.upcast()))
}
- &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()))
- });
+ 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")))
}
_ => 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/tests/method_resolution.rs b/crates/hir_ty/src/tests/method_resolution.rs
index 011347e5c4..d97147541a 100644
--- a/crates/hir_ty/src/tests/method_resolution.rs
+++ b/crates/hir_ty/src/tests/method_resolution.rs
@@ -6,33 +6,39 @@ use super::{check_infer, check_no_mismatches, check_types};
#[test]
fn infer_slice_method() {
- check_infer(
+ check_types(
r#"
- #[lang = "slice"]
- impl<T> [T] {
- fn foo(&self) -> T {
- loop {}
- }
- }
-
- #[lang = "slice_alloc"]
- impl<T> [T] {}
+impl<T> [T] {
+ fn foo(&self) -> T {
+ loop {}
+ }
+}
- fn test(x: &[u8]) {
- <[_]>::foo(x);
- }
+fn test(x: &[u8]) {
+ <[_]>::foo(x);
+ //^^^^^^^^^^^^^ u8
+}
"#,
- 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]
- "#]],
+ );
+}
+
+#[test]
+fn cross_crate_primitive_method() {
+ check_types(
+ r#"
+//- /main.rs crate:main deps:other_crate
+fn test() {
+ let x = 1f32;
+ x.foo();
+} //^^^^^^^ f32
+
+//- /lib.rs crate:other_crate
+mod foo {
+ impl f32 {
+ pub fn foo(self) -> f32 { 0. }
+ }
+}
+"#,
);
}
@@ -40,16 +46,15 @@ fn infer_slice_method() {
fn infer_array_inherent_impl() {
check_types(
r#"
- #[lang = "array"]
- impl<T, const N: usize> [T; N] {
- fn foo(&self) -> T {
- loop {}
- }
- }
- fn test(x: &[u8; 0]) {
- <[_; 0]>::foo(x);
- //^^^^^^^^^^^^^^^^ u8
- }
+impl<T, const N: usize> [T; N] {
+ fn foo(&self) -> T {
+ loop {}
+ }
+}
+fn test(x: &[u8; 0]) {
+ <[_; 0]>::foo(x);
+ //^^^^^^^^^^^^^^^^ u8
+}
"#,
);
}