mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-10-01 22:31:43 +00:00
Split and document array method resolution logic.
This commit is contained in:
parent
9593fe684d
commit
ebb891246c
1 changed files with 53 additions and 34 deletions
|
@ -709,6 +709,33 @@ fn iterate_trait_method_candidates(
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn filter_inherent_impls_for_self_ty<'i>(
|
||||||
|
impls: &'i InherentImpls,
|
||||||
|
self_ty: &Ty,
|
||||||
|
) -> impl Iterator<Item = &'i ImplId> {
|
||||||
|
// inherent methods on arrays are fingerprinted as [T; {unknown}], so we must also consider them when
|
||||||
|
// resolving a method call on an array with a known len
|
||||||
|
let array_impls = {
|
||||||
|
if let TyKind::Array(parameters, array_len) = self_ty.kind(&Interner) {
|
||||||
|
if !array_len.is_unknown() {
|
||||||
|
let unknown_array_len_ty =
|
||||||
|
TyKind::Array(parameters.clone(), consteval::usize_const(None))
|
||||||
|
.intern(&Interner);
|
||||||
|
|
||||||
|
Some(impls.for_self_ty(&unknown_array_len_ty))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.into_iter()
|
||||||
|
.flatten();
|
||||||
|
|
||||||
|
impls.for_self_ty(self_ty).iter().chain(array_impls)
|
||||||
|
}
|
||||||
|
|
||||||
fn iterate_inherent_methods(
|
fn iterate_inherent_methods(
|
||||||
self_ty: &Canonical<Ty>,
|
self_ty: &Canonical<Ty>,
|
||||||
db: &dyn HirDatabase,
|
db: &dyn HirDatabase,
|
||||||
|
@ -726,25 +753,7 @@ fn iterate_inherent_methods(
|
||||||
for krate in def_crates {
|
for krate in def_crates {
|
||||||
let impls = db.inherent_impls_in_crate(krate);
|
let impls = db.inherent_impls_in_crate(krate);
|
||||||
|
|
||||||
let impls_for_self_ty = impls.for_self_ty(&self_ty.value).iter().chain(
|
let impls_for_self_ty = filter_inherent_impls_for_self_ty(&impls, &self_ty.value);
|
||||||
{
|
|
||||||
if let TyKind::Array(parameters, array_len) = self_ty.value.kind(&Interner) {
|
|
||||||
if !array_len.is_unknown() {
|
|
||||||
let unknown_array_len_ty =
|
|
||||||
TyKind::Array(parameters.clone(), consteval::usize_const(None))
|
|
||||||
.intern(&Interner);
|
|
||||||
|
|
||||||
Some(impls.for_self_ty(&unknown_array_len_ty))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.into_iter()
|
|
||||||
.flatten(),
|
|
||||||
);
|
|
||||||
|
|
||||||
for &impl_def in impls_for_self_ty {
|
for &impl_def in impls_for_self_ty {
|
||||||
for &item in db.impl_data(impl_def).items.iter() {
|
for &item in db.impl_data(impl_def).items.iter() {
|
||||||
|
@ -798,6 +807,28 @@ pub fn resolve_indexing_op(
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_transformed_receiver_ty_equal(transformed_receiver_ty: &Ty, receiver_ty: &Ty) -> bool {
|
||||||
|
if transformed_receiver_ty == receiver_ty {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// a transformed receiver may be considered equal (and a valid method call candidate) if it is an array
|
||||||
|
// with an unknown (i.e. generic) length, and the receiver is an array with the same item type but a known len,
|
||||||
|
// this allows inherent methods on arrays to be considered valid resolution candidates
|
||||||
|
match (transformed_receiver_ty.kind(&Interner), receiver_ty.kind(&Interner)) {
|
||||||
|
(
|
||||||
|
TyKind::Array(transformed_array_ty, transformed_array_len),
|
||||||
|
TyKind::Array(receiver_array_ty, receiver_array_len),
|
||||||
|
) if transformed_array_ty == receiver_array_ty
|
||||||
|
&& transformed_array_len.is_unknown()
|
||||||
|
&& !receiver_array_len.is_unknown() =>
|
||||||
|
{
|
||||||
|
true
|
||||||
|
}
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn is_valid_candidate(
|
fn is_valid_candidate(
|
||||||
db: &dyn HirDatabase,
|
db: &dyn HirDatabase,
|
||||||
env: Arc<TraitEnvironment>,
|
env: Arc<TraitEnvironment>,
|
||||||
|
@ -823,23 +854,11 @@ fn is_valid_candidate(
|
||||||
Some(ty) => ty,
|
Some(ty) => ty,
|
||||||
None => return false,
|
None => return false,
|
||||||
};
|
};
|
||||||
if transformed_receiver_ty != receiver_ty.value {
|
|
||||||
match (
|
if !is_transformed_receiver_ty_equal(&transformed_receiver_ty, &receiver_ty.value) {
|
||||||
transformed_receiver_ty.kind(&Interner),
|
|
||||||
receiver_ty.value.kind(&Interner),
|
|
||||||
) {
|
|
||||||
(
|
|
||||||
TyKind::Array(transformed_array_ty, transformed_array_len),
|
|
||||||
TyKind::Array(receiver_array_ty, receiver_array_len),
|
|
||||||
) if transformed_array_ty == receiver_array_ty
|
|
||||||
&& transformed_array_len.is_unknown()
|
|
||||||
&& !receiver_array_len.is_unknown() => {}
|
|
||||||
_ => {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
if let Some(from_module) = visible_from_module {
|
if let Some(from_module) = visible_from_module {
|
||||||
if !db.function_visibility(m).is_visible_from(db.upcast(), from_module) {
|
if !db.function_visibility(m).is_visible_from(db.upcast(), from_module) {
|
||||||
cov_mark::hit!(autoderef_candidate_not_visible);
|
cov_mark::hit!(autoderef_candidate_not_visible);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue