mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-30 13:51:31 +00:00
Do autoderef for indexing
This commit is contained in:
parent
e313efb992
commit
31171eed5e
4 changed files with 74 additions and 7 deletions
|
@ -28,7 +28,7 @@ use hir_def::{
|
||||||
path::{path, Path},
|
path::{path, Path},
|
||||||
resolver::{HasResolver, Resolver, TypeNs},
|
resolver::{HasResolver, Resolver, TypeNs},
|
||||||
type_ref::{Mutability, TypeRef},
|
type_ref::{Mutability, TypeRef},
|
||||||
AdtId, AssocItemId, DefWithBodyId, FunctionId, StructFieldId, TypeAliasId, VariantId,
|
AdtId, AssocItemId, DefWithBodyId, FunctionId, StructFieldId, TraitId, TypeAliasId, VariantId,
|
||||||
};
|
};
|
||||||
use hir_expand::{diagnostics::DiagnosticSink, name::name};
|
use hir_expand::{diagnostics::DiagnosticSink, name::name};
|
||||||
use ra_arena::map::ArenaMap;
|
use ra_arena::map::ArenaMap;
|
||||||
|
@ -540,8 +540,12 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||||
Some(struct_.into())
|
Some(struct_.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn resolve_ops_index(&self) -> Option<TraitId> {
|
||||||
|
self.resolve_lang_item("index")?.as_trait()
|
||||||
|
}
|
||||||
|
|
||||||
fn resolve_ops_index_output(&self) -> Option<TypeAliasId> {
|
fn resolve_ops_index_output(&self) -> Option<TypeAliasId> {
|
||||||
let trait_ = self.resolve_lang_item("index")?.as_trait()?;
|
let trait_ = self.resolve_ops_index()?;
|
||||||
self.db.trait_data(trait_).associated_type_by_name(&name![Output])
|
self.db.trait_data(trait_).associated_type_by_name(&name![Output])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -429,11 +429,27 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||||
let base_ty = self.infer_expr_inner(*base, &Expectation::none());
|
let base_ty = self.infer_expr_inner(*base, &Expectation::none());
|
||||||
let index_ty = self.infer_expr(*index, &Expectation::none());
|
let index_ty = self.infer_expr(*index, &Expectation::none());
|
||||||
|
|
||||||
self.resolve_associated_type_with_params(
|
if let (Some(index_trait), Some(krate)) =
|
||||||
base_ty,
|
(self.resolve_ops_index(), self.resolver.krate())
|
||||||
self.resolve_ops_index_output(),
|
{
|
||||||
&[index_ty],
|
let canonicalized = self.canonicalizer().canonicalize_ty(base_ty);
|
||||||
)
|
let self_ty = method_resolution::resolve_indexing_op(
|
||||||
|
self.db,
|
||||||
|
&canonicalized.value,
|
||||||
|
self.trait_env.clone(),
|
||||||
|
krate,
|
||||||
|
index_trait,
|
||||||
|
);
|
||||||
|
let self_ty =
|
||||||
|
self_ty.map_or(Ty::Unknown, |t| canonicalized.decanonicalize_ty(t.value));
|
||||||
|
self.resolve_associated_type_with_params(
|
||||||
|
self_ty,
|
||||||
|
self.resolve_ops_index_output(),
|
||||||
|
&[index_ty],
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
Ty::Unknown
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Expr::Tuple { exprs } => {
|
Expr::Tuple { exprs } => {
|
||||||
let mut tys = match &expected.ty {
|
let mut tys = match &expected.ty {
|
||||||
|
|
|
@ -447,6 +447,25 @@ fn iterate_inherent_methods<T>(
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the self type for the index trait call.
|
||||||
|
pub fn resolve_indexing_op(
|
||||||
|
db: &impl HirDatabase,
|
||||||
|
ty: &Canonical<Ty>,
|
||||||
|
env: Arc<TraitEnvironment>,
|
||||||
|
krate: CrateId,
|
||||||
|
index_trait: TraitId,
|
||||||
|
) -> Option<Canonical<Ty>> {
|
||||||
|
let ty = InEnvironment { value: ty.clone(), environment: env.clone() };
|
||||||
|
let deref_chain = autoderef_method_receiver(db, krate, ty);
|
||||||
|
for ty in deref_chain {
|
||||||
|
let goal = generic_implements_goal(db, env.clone(), index_trait, ty.clone());
|
||||||
|
if db.trait_solve(krate, goal).is_some() {
|
||||||
|
return Some(ty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
fn is_valid_candidate(
|
fn is_valid_candidate(
|
||||||
db: &impl HirDatabase,
|
db: &impl HirDatabase,
|
||||||
name: Option<&Name>,
|
name: Option<&Name>,
|
||||||
|
|
|
@ -567,6 +567,34 @@ mod ops {
|
||||||
assert_eq!("Foo", type_at_pos(&db, pos));
|
assert_eq!("Foo", type_at_pos(&db, pos));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn infer_ops_index_autoderef() {
|
||||||
|
let (db, pos) = TestDB::with_position(
|
||||||
|
r#"
|
||||||
|
//- /main.rs crate:main deps:std
|
||||||
|
fn test() {
|
||||||
|
let a = &[1u32, 2, 3];
|
||||||
|
let b = a[1];
|
||||||
|
b<|>;
|
||||||
|
}
|
||||||
|
|
||||||
|
//- /std.rs crate:std
|
||||||
|
impl<T> ops::Index<u32> for [T] {
|
||||||
|
type Output = T;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[prelude_import] use ops::*;
|
||||||
|
mod ops {
|
||||||
|
#[lang = "index"]
|
||||||
|
pub trait Index<Idx> {
|
||||||
|
type Output;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
assert_eq!("u32", type_at_pos(&db, pos));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn deref_trait() {
|
fn deref_trait() {
|
||||||
let t = type_at(
|
let t = type_at(
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue