diff options
-rw-r--r-- | crates/ra_hir_ty/src/infer.rs | 8 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/infer/expr.rs | 26 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/method_resolution.rs | 19 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/tests/traits.rs | 28 |
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 | }; |
33 | use hir_expand::{diagnostics::DiagnosticSink, name::name}; | 33 | use hir_expand::{diagnostics::DiagnosticSink, name::name}; |
34 | use ra_arena::map::ArenaMap; | 34 | use 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. | ||
451 | pub 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 | |||
450 | fn is_valid_candidate( | 469 | fn 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] |
571 | fn infer_ops_index_autoderef() { | ||
572 | let (db, pos) = TestDB::with_position( | ||
573 | r#" | ||
574 | //- /main.rs crate:main deps:std | ||
575 | fn test() { | ||
576 | let a = &[1u32, 2, 3]; | ||
577 | let b = a[1]; | ||
578 | b<|>; | ||
579 | } | ||
580 | |||
581 | //- /std.rs crate:std | ||
582 | impl<T> ops::Index<u32> for [T] { | ||
583 | type Output = T; | ||
584 | } | ||
585 | |||
586 | #[prelude_import] use ops::*; | ||
587 | mod 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] | ||
571 | fn deref_trait() { | 599 | fn deref_trait() { |
572 | let t = type_at( | 600 | let t = type_at( |
573 | r#" | 601 | r#" |