Skip to content

Commit b898808

Browse files
committed
fix: Don't rely on lang items to find primitive impls
rustc has removed the use of lang items to mark the primitive impls, so just look through the crate graph for them (this should be fine performance-wise since we cache the crates that contain these impls). Fixes #11876.
1 parent 5fe366c commit b898808

File tree

3 files changed

+92
-90
lines changed

3 files changed

+92
-90
lines changed

crates/hir_ty/src/db.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
44
use std::sync::Arc;
55

6+
use arrayvec::ArrayVec;
67
use base_db::{impl_intern_key, salsa, CrateId, Upcast};
78
use hir_def::{
89
db::DefDatabase, expr::ExprId, BlockId, ConstId, ConstParamId, DefWithBodyId, FunctionId,
@@ -13,7 +14,7 @@ use la_arena::ArenaMap;
1314
use crate::{
1415
chalk_db,
1516
consteval::{ComputedExpr, ConstEvalError},
16-
method_resolution::{InherentImpls, TraitImpls},
17+
method_resolution::{InherentImpls, TraitImpls, TyFingerprint},
1718
Binders, CallableDefId, FnDefId, GenericArg, ImplTraitId, InferenceResult, Interner, PolyFnSig,
1819
QuantifiedWhereClause, ReturnTypeImplTraits, TraitRef, Ty, TyDefId, ValueTyDefId,
1920
};
@@ -86,6 +87,12 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
8687
#[salsa::invoke(InherentImpls::inherent_impls_in_block_query)]
8788
fn inherent_impls_in_block(&self, block: BlockId) -> Option<Arc<InherentImpls>>;
8889

90+
/// Collects all crates in the dependency graph that have impls for the
91+
/// given fingerprint. This is only used for primitive types; for
92+
/// user-defined types we just look at the crate where the type is defined.
93+
#[salsa::invoke(crate::method_resolution::inherent_impl_crates_query)]
94+
fn inherent_impl_crates(&self, krate: CrateId, fp: TyFingerprint) -> ArrayVec<CrateId, 2>;
95+
8996
#[salsa::invoke(TraitImpls::trait_impls_in_crate_query)]
9097
fn trait_impls_in_crate(&self, krate: CrateId) -> Arc<TraitImpls>;
9198

crates/hir_ty/src/method_resolution.rs

+45-55
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,8 @@ use arrayvec::ArrayVec;
88
use base_db::{CrateId, Edition};
99
use chalk_ir::{cast::Cast, Mutability, UniverseIndex};
1010
use hir_def::{
11-
item_scope::ItemScope, lang_item::LangItemTarget, nameres::DefMap, AssocItemId, BlockId,
12-
ConstId, FunctionId, GenericDefId, HasModule, ImplId, ItemContainerId, Lookup, ModuleDefId,
13-
ModuleId, TraitId,
11+
item_scope::ItemScope, nameres::DefMap, AssocItemId, BlockId, ConstId, FunctionId,
12+
GenericDefId, HasModule, ImplId, ItemContainerId, Lookup, ModuleDefId, ModuleId, TraitId,
1413
};
1514
use hir_expand::name::Name;
1615
use rustc_hash::{FxHashMap, FxHashSet};
@@ -21,7 +20,7 @@ use crate::{
2120
db::HirDatabase,
2221
from_foreign_def_id,
2322
infer::{unify::InferenceTable, Adjust, Adjustment, AutoBorrow, OverloadedDeref, PointerCast},
24-
primitive::{self, FloatTy, IntTy, UintTy},
23+
primitive::{FloatTy, IntTy, UintTy},
2524
static_lifetime,
2625
utils::all_super_traits,
2726
AdtId, Canonical, CanonicalVarKinds, DebruijnIndex, ForeignDefId, InEnvironment, Interner,
@@ -337,6 +336,30 @@ impl InherentImpls {
337336
}
338337
}
339338

339+
pub fn inherent_impl_crates_query(
340+
db: &dyn HirDatabase,
341+
krate: CrateId,
342+
fp: TyFingerprint,
343+
) -> ArrayVec<CrateId, 2> {
344+
let _p = profile::span("inherent_impl_crates_query");
345+
let mut res = ArrayVec::new();
346+
let crate_graph = db.crate_graph();
347+
348+
for krate in crate_graph.transitive_deps(krate) {
349+
if res.is_full() {
350+
// we don't currently look for or store more than two crates here,
351+
// so don't needlessly look at more crates than necessary.
352+
break;
353+
}
354+
let impls = db.inherent_impls_in_crate(krate);
355+
if impls.map.get(&fp).map_or(false, |v| !v.is_empty()) {
356+
res.push(krate);
357+
}
358+
}
359+
360+
res
361+
}
362+
340363
fn collect_unnamed_consts<'a>(
341364
db: &'a dyn HirDatabase,
342365
scope: &'a ItemScope,
@@ -370,63 +393,30 @@ pub fn def_crates(
370393
ty: &Ty,
371394
cur_crate: CrateId,
372395
) -> Option<ArrayVec<CrateId, 2>> {
373-
// Types like slice can have inherent impls in several crates, (core and alloc).
374-
// The corresponding impls are marked with lang items, so we can use them to find the required crates.
375-
macro_rules! lang_item_crate {
376-
($($name:expr),+ $(,)?) => {{
377-
let mut v = ArrayVec::<LangItemTarget, 2>::new();
378-
$(
379-
v.extend(db.lang_item(cur_crate, $name.into()));
380-
)+
381-
v
382-
}};
383-
}
384-
385396
let mod_to_crate_ids = |module: ModuleId| Some(iter::once(module.krate()).collect());
386397

387-
let lang_item_targets = match ty.kind(Interner) {
388-
TyKind::Adt(AdtId(def_id), _) => {
389-
return mod_to_crate_ids(def_id.module(db.upcast()));
390-
}
398+
let fp = TyFingerprint::for_inherent_impl(ty);
399+
400+
match ty.kind(Interner) {
401+
TyKind::Adt(AdtId(def_id), _) => mod_to_crate_ids(def_id.module(db.upcast())),
391402
TyKind::Foreign(id) => {
392-
return mod_to_crate_ids(
393-
from_foreign_def_id(*id).lookup(db.upcast()).module(db.upcast()),
394-
);
395-
}
396-
TyKind::Scalar(Scalar::Bool) => lang_item_crate!("bool"),
397-
TyKind::Scalar(Scalar::Char) => lang_item_crate!("char"),
398-
TyKind::Scalar(Scalar::Float(f)) => match f {
399-
// There are two lang items: one in libcore (fXX) and one in libstd (fXX_runtime)
400-
FloatTy::F32 => lang_item_crate!("f32", "f32_runtime"),
401-
FloatTy::F64 => lang_item_crate!("f64", "f64_runtime"),
402-
},
403-
&TyKind::Scalar(Scalar::Int(t)) => {
404-
lang_item_crate!(primitive::int_ty_to_string(t))
403+
mod_to_crate_ids(from_foreign_def_id(*id).lookup(db.upcast()).module(db.upcast()))
405404
}
406-
&TyKind::Scalar(Scalar::Uint(t)) => {
407-
lang_item_crate!(primitive::uint_ty_to_string(t))
408-
}
409-
TyKind::Str => lang_item_crate!("str_alloc", "str"),
410-
TyKind::Slice(_) => lang_item_crate!("slice_alloc", "slice"),
411-
TyKind::Array(..) => lang_item_crate!("array"),
412-
TyKind::Raw(Mutability::Not, _) => lang_item_crate!("const_ptr"),
413-
TyKind::Raw(Mutability::Mut, _) => lang_item_crate!("mut_ptr"),
414-
TyKind::Dyn(_) => {
415-
return ty.dyn_trait().and_then(|trait_| {
416-
mod_to_crate_ids(GenericDefId::TraitId(trait_).module(db.upcast()))
417-
});
405+
TyKind::Dyn(_) => ty
406+
.dyn_trait()
407+
.and_then(|trait_| mod_to_crate_ids(GenericDefId::TraitId(trait_).module(db.upcast()))),
408+
// for primitives, there may be impls in various places (core and alloc
409+
// mostly). We just check the whole crate graph for crates with impls
410+
// (cached behind a query).
411+
TyKind::Scalar(_)
412+
| TyKind::Str
413+
| TyKind::Slice(_)
414+
| TyKind::Array(..)
415+
| TyKind::Raw(..) => {
416+
Some(db.inherent_impl_crates(cur_crate, fp.expect("fingerprint for primitive")))
418417
}
419418
_ => return None,
420-
};
421-
let res = lang_item_targets
422-
.into_iter()
423-
.filter_map(|it| match it {
424-
LangItemTarget::ImplDefId(it) => Some(it),
425-
_ => None,
426-
})
427-
.map(|it| it.lookup(db.upcast()).container.krate())
428-
.collect();
429-
Some(res)
419+
}
430420
}
431421

432422
/// Look up the method with the given name.

crates/hir_ty/src/tests/method_resolution.rs

+39-34
Original file line numberDiff line numberDiff line change
@@ -6,50 +6,55 @@ use super::{check_infer, check_no_mismatches, check_types};
66

77
#[test]
88
fn infer_slice_method() {
9-
check_infer(
9+
check_types(
1010
r#"
11-
#[lang = "slice"]
12-
impl<T> [T] {
13-
fn foo(&self) -> T {
14-
loop {}
15-
}
16-
}
17-
18-
#[lang = "slice_alloc"]
19-
impl<T> [T] {}
11+
impl<T> [T] {
12+
fn foo(&self) -> T {
13+
loop {}
14+
}
15+
}
2016
21-
fn test(x: &[u8]) {
22-
<[_]>::foo(x);
23-
}
17+
fn test(x: &[u8]) {
18+
<[_]>::foo(x);
19+
//^^^^^^^^^^^^^ u8
20+
}
2421
"#,
25-
expect![[r#"
26-
44..48 'self': &[T]
27-
55..78 '{ ... }': T
28-
65..72 'loop {}': !
29-
70..72 '{}': ()
30-
130..131 'x': &[u8]
31-
140..162 '{ ...(x); }': ()
32-
146..156 '<[_]>::foo': fn foo<u8>(&[u8]) -> u8
33-
146..159 '<[_]>::foo(x)': u8
34-
157..158 'x': &[u8]
35-
"#]],
22+
);
23+
}
24+
25+
#[test]
26+
fn cross_crate_primitive_method() {
27+
check_types(
28+
r#"
29+
//- /main.rs crate:main deps:other_crate
30+
fn test() {
31+
let x = 1f32;
32+
x.foo();
33+
} //^^^^^^^ f32
34+
35+
//- /lib.rs crate:other_crate
36+
mod foo {
37+
impl f32 {
38+
pub fn foo(self) -> f32 { 0. }
39+
}
40+
}
41+
"#,
3642
);
3743
}
3844

3945
#[test]
4046
fn infer_array_inherent_impl() {
4147
check_types(
4248
r#"
43-
#[lang = "array"]
44-
impl<T, const N: usize> [T; N] {
45-
fn foo(&self) -> T {
46-
loop {}
47-
}
48-
}
49-
fn test(x: &[u8; 0]) {
50-
<[_; 0]>::foo(x);
51-
//^^^^^^^^^^^^^^^^ u8
52-
}
49+
impl<T, const N: usize> [T; N] {
50+
fn foo(&self) -> T {
51+
loop {}
52+
}
53+
}
54+
fn test(x: &[u8; 0]) {
55+
<[_; 0]>::foo(x);
56+
//^^^^^^^^^^^^^^^^ u8
57+
}
5358
"#,
5459
);
5560
}

0 commit comments

Comments
 (0)