Skip to content

Commit 0ff3d56

Browse files
Merge #11881
11881: fix: Don't rely on lang items to find primitive impls r=flodiebold a=flodiebold 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. Co-authored-by: Florian Diebold <[email protected]>
2 parents 5fe366c + b898808 commit 0ff3d56

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)