Skip to content

Commit 108b080

Browse files
bors[bot]yotamofek
andauthored
Merge #10180
10180: Fix resolution for inherent array methods r=flodiebold a=yotamofek My second attempt at fixing #9992 , previous attempt was here: #10017 , but the logic was broken. I know that this is not an ideal solution.... that would require, IIUC, a pretty big overhaul of the const generics handling in `rust-analyzer`. But, given that some of the array methods were/are being stabilized (e.g. rust-lang/rust#87174 ), I think it'll be very beneficial to `rust-analyzer` users to have some preliminary support for them. (I know it's something I've been running into quite a lot lately :) ) As far as my limited understanding of this project's architecture goes, I think this isn't the worst hack in the world, and shouldn't be too much of a hassle to undo if/when const generics become better supported. If the maintainers deem this approach viable, I'll want to add some comments, emphasizing the purpose of this code, and that it should be removed at some point in the future. Co-authored-by: Yotam Ofek <[email protected]>
2 parents 3dae94b + ebb8912 commit 108b080

File tree

2 files changed

+84
-2
lines changed

2 files changed

+84
-2
lines changed

crates/hir_ty/src/method_resolution.rs

+55-2
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use rustc_hash::{FxHashMap, FxHashSet};
1616

1717
use crate::{
1818
autoderef,
19+
consteval::{self, ConstExt},
1920
db::HirDatabase,
2021
from_foreign_def_id,
2122
primitive::{self, FloatTy, IntTy, UintTy},
@@ -708,6 +709,33 @@ fn iterate_trait_method_candidates(
708709
false
709710
}
710711

712+
fn filter_inherent_impls_for_self_ty<'i>(
713+
impls: &'i InherentImpls,
714+
self_ty: &Ty,
715+
) -> impl Iterator<Item = &'i ImplId> {
716+
// inherent methods on arrays are fingerprinted as [T; {unknown}], so we must also consider them when
717+
// resolving a method call on an array with a known len
718+
let array_impls = {
719+
if let TyKind::Array(parameters, array_len) = self_ty.kind(&Interner) {
720+
if !array_len.is_unknown() {
721+
let unknown_array_len_ty =
722+
TyKind::Array(parameters.clone(), consteval::usize_const(None))
723+
.intern(&Interner);
724+
725+
Some(impls.for_self_ty(&unknown_array_len_ty))
726+
} else {
727+
None
728+
}
729+
} else {
730+
None
731+
}
732+
}
733+
.into_iter()
734+
.flatten();
735+
736+
impls.for_self_ty(self_ty).iter().chain(array_impls)
737+
}
738+
711739
fn iterate_inherent_methods(
712740
self_ty: &Canonical<Ty>,
713741
db: &dyn HirDatabase,
@@ -725,7 +753,9 @@ fn iterate_inherent_methods(
725753
for krate in def_crates {
726754
let impls = db.inherent_impls_in_crate(krate);
727755

728-
for &impl_def in impls.for_self_ty(&self_ty.value) {
756+
let impls_for_self_ty = filter_inherent_impls_for_self_ty(&impls, &self_ty.value);
757+
758+
for &impl_def in impls_for_self_ty {
729759
for &item in db.impl_data(impl_def).items.iter() {
730760
if !is_valid_candidate(
731761
db,
@@ -777,6 +807,28 @@ pub fn resolve_indexing_op(
777807
None
778808
}
779809

810+
fn is_transformed_receiver_ty_equal(transformed_receiver_ty: &Ty, receiver_ty: &Ty) -> bool {
811+
if transformed_receiver_ty == receiver_ty {
812+
return true;
813+
}
814+
815+
// a transformed receiver may be considered equal (and a valid method call candidate) if it is an array
816+
// with an unknown (i.e. generic) length, and the receiver is an array with the same item type but a known len,
817+
// this allows inherent methods on arrays to be considered valid resolution candidates
818+
match (transformed_receiver_ty.kind(&Interner), receiver_ty.kind(&Interner)) {
819+
(
820+
TyKind::Array(transformed_array_ty, transformed_array_len),
821+
TyKind::Array(receiver_array_ty, receiver_array_len),
822+
) if transformed_array_ty == receiver_array_ty
823+
&& transformed_array_len.is_unknown()
824+
&& !receiver_array_len.is_unknown() =>
825+
{
826+
true
827+
}
828+
_ => false,
829+
}
830+
}
831+
780832
fn is_valid_candidate(
781833
db: &dyn HirDatabase,
782834
env: Arc<TraitEnvironment>,
@@ -802,7 +854,8 @@ fn is_valid_candidate(
802854
Some(ty) => ty,
803855
None => return false,
804856
};
805-
if transformed_receiver_ty != receiver_ty.value {
857+
858+
if !is_transformed_receiver_ty_equal(&transformed_receiver_ty, &receiver_ty.value) {
806859
return false;
807860
}
808861
}

crates/hir_ty/src/tests/method_resolution.rs

+29
Original file line numberDiff line numberDiff line change
@@ -1283,6 +1283,35 @@ fn f() {
12831283
);
12841284
}
12851285

1286+
#[test]
1287+
fn resolve_const_generic_array_methods() {
1288+
check_types(
1289+
r#"
1290+
#[lang = "array"]
1291+
impl<T, const N: usize> [T; N] {
1292+
pub fn map<F, U>(self, f: F) -> [U; N]
1293+
where
1294+
F: FnMut(T) -> U,
1295+
{ loop {} }
1296+
}
1297+
1298+
#[lang = "slice"]
1299+
impl<T> [T] {
1300+
pub fn map<F, U>(self, f: F) -> &[U]
1301+
where
1302+
F: FnMut(T) -> U,
1303+
{ loop {} }
1304+
}
1305+
1306+
fn f() {
1307+
let v = [1, 2].map::<_, usize>(|x| -> x * 2);
1308+
v;
1309+
//^ [usize; _]
1310+
}
1311+
"#,
1312+
);
1313+
}
1314+
12861315
#[test]
12871316
fn skip_array_during_method_dispatch() {
12881317
check_types(

0 commit comments

Comments
 (0)