aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_ty
diff options
context:
space:
mode:
authorFlorian Diebold <[email protected]>2020-02-29 21:48:23 +0000
committerFlorian Diebold <[email protected]>2020-02-29 21:48:53 +0000
commit31171eed5eeab217280237e63ffe6adda62baf96 (patch)
tree0597ebf09ac6c3216477c4993a8f16686f0ca452 /crates/ra_hir_ty
parente313efb9926be80a5d7614d800e425b6891cf7d9 (diff)
Do autoderef for indexing
Diffstat (limited to 'crates/ra_hir_ty')
-rw-r--r--crates/ra_hir_ty/src/infer.rs8
-rw-r--r--crates/ra_hir_ty/src/infer/expr.rs26
-rw-r--r--crates/ra_hir_ty/src/method_resolution.rs19
-rw-r--r--crates/ra_hir_ty/src/tests/traits.rs28
4 files changed, 74 insertions, 7 deletions
diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs
index 569d46cc3..377f44fa7 100644
--- a/crates/ra_hir_ty/src/infer.rs
+++ b/crates/ra_hir_ty/src/infer.rs
@@ -28,7 +28,7 @@ use hir_def::{
28 path::{path, Path}, 28 path::{path, Path},
29 resolver::{HasResolver, Resolver, TypeNs}, 29 resolver::{HasResolver, Resolver, TypeNs},
30 type_ref::{Mutability, TypeRef}, 30 type_ref::{Mutability, TypeRef},
31 AdtId, AssocItemId, DefWithBodyId, FunctionId, StructFieldId, TypeAliasId, VariantId, 31 AdtId, AssocItemId, DefWithBodyId, FunctionId, StructFieldId, TraitId, TypeAliasId, VariantId,
32}; 32};
33use hir_expand::{diagnostics::DiagnosticSink, name::name}; 33use hir_expand::{diagnostics::DiagnosticSink, name::name};
34use ra_arena::map::ArenaMap; 34use ra_arena::map::ArenaMap;
@@ -540,8 +540,12 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
540 Some(struct_.into()) 540 Some(struct_.into())
541 } 541 }
542 542
543 fn resolve_ops_index(&self) -> Option<TraitId> {
544 self.resolve_lang_item("index")?.as_trait()
545 }
546
543 fn resolve_ops_index_output(&self) -> Option<TypeAliasId> { 547 fn resolve_ops_index_output(&self) -> Option<TypeAliasId> {
544 let trait_ = self.resolve_lang_item("index")?.as_trait()?; 548 let trait_ = self.resolve_ops_index()?;
545 self.db.trait_data(trait_).associated_type_by_name(&name![Output]) 549 self.db.trait_data(trait_).associated_type_by_name(&name![Output])
546 } 550 }
547} 551}
diff --git a/crates/ra_hir_ty/src/infer/expr.rs b/crates/ra_hir_ty/src/infer/expr.rs
index 3db5b2b51..e89cc7298 100644
--- a/crates/ra_hir_ty/src/infer/expr.rs
+++ b/crates/ra_hir_ty/src/infer/expr.rs
@@ -429,11 +429,27 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
429 let base_ty = self.infer_expr_inner(*base, &Expectation::none()); 429 let base_ty = self.infer_expr_inner(*base, &Expectation::none());
430 let index_ty = self.infer_expr(*index, &Expectation::none()); 430 let index_ty = self.infer_expr(*index, &Expectation::none());
431 431
432 self.resolve_associated_type_with_params( 432 if let (Some(index_trait), Some(krate)) =
433 base_ty, 433 (self.resolve_ops_index(), self.resolver.krate())
434 self.resolve_ops_index_output(), 434 {
435 &[index_ty], 435 let canonicalized = self.canonicalizer().canonicalize_ty(base_ty);
436 ) 436 let self_ty = method_resolution::resolve_indexing_op(
437 self.db,
438 &canonicalized.value,
439 self.trait_env.clone(),
440 krate,
441 index_trait,
442 );
443 let self_ty =
444 self_ty.map_or(Ty::Unknown, |t| canonicalized.decanonicalize_ty(t.value));
445 self.resolve_associated_type_with_params(
446 self_ty,
447 self.resolve_ops_index_output(),
448 &[index_ty],
449 )
450 } else {
451 Ty::Unknown
452 }
437 } 453 }
438 Expr::Tuple { exprs } => { 454 Expr::Tuple { exprs } => {
439 let mut tys = match &expected.ty { 455 let mut tys = match &expected.ty {
diff --git a/crates/ra_hir_ty/src/method_resolution.rs b/crates/ra_hir_ty/src/method_resolution.rs
index 7b0ff8161..74b908c2e 100644
--- a/crates/ra_hir_ty/src/method_resolution.rs
+++ b/crates/ra_hir_ty/src/method_resolution.rs
@@ -447,6 +447,25 @@ fn iterate_inherent_methods<T>(
447 None 447 None
448} 448}
449 449
450/// Returns the self type for the index trait call.
451pub fn resolve_indexing_op(
452 db: &impl HirDatabase,
453 ty: &Canonical<Ty>,
454 env: Arc<TraitEnvironment>,
455 krate: CrateId,
456 index_trait: TraitId,
457) -> Option<Canonical<Ty>> {
458 let ty = InEnvironment { value: ty.clone(), environment: env.clone() };
459 let deref_chain = autoderef_method_receiver(db, krate, ty);
460 for ty in deref_chain {
461 let goal = generic_implements_goal(db, env.clone(), index_trait, ty.clone());
462 if db.trait_solve(krate, goal).is_some() {
463 return Some(ty);
464 }
465 }
466 None
467}
468
450fn is_valid_candidate( 469fn is_valid_candidate(
451 db: &impl HirDatabase, 470 db: &impl HirDatabase,
452 name: Option<&Name>, 471 name: Option<&Name>,
diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs
index 7d796d0b9..547010b35 100644
--- a/crates/ra_hir_ty/src/tests/traits.rs
+++ b/crates/ra_hir_ty/src/tests/traits.rs
@@ -568,6 +568,34 @@ mod ops {
568} 568}
569 569
570#[test] 570#[test]
571fn infer_ops_index_autoderef() {
572 let (db, pos) = TestDB::with_position(
573 r#"
574//- /main.rs crate:main deps:std
575fn test() {
576 let a = &[1u32, 2, 3];
577 let b = a[1];
578 b<|>;
579}
580
581//- /std.rs crate:std
582impl<T> ops::Index<u32> for [T] {
583 type Output = T;
584}
585
586#[prelude_import] use ops::*;
587mod ops {
588 #[lang = "index"]
589 pub trait Index<Idx> {
590 type Output;
591 }
592}
593"#,
594 );
595 assert_eq!("u32", type_at_pos(&db, pos));
596}
597
598#[test]
571fn deref_trait() { 599fn deref_trait() {
572 let t = type_at( 600 let t = type_at(
573 r#" 601 r#"