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 | 40 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/tests/method_resolution.rs | 18 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/tests/traits.rs | 28 |
5 files changed, 111 insertions, 9 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 df5901835..74b908c2e 100644 --- a/crates/ra_hir_ty/src/method_resolution.rs +++ b/crates/ra_hir_ty/src/method_resolution.rs | |||
@@ -20,7 +20,7 @@ use crate::{ | |||
20 | db::HirDatabase, | 20 | db::HirDatabase, |
21 | primitive::{FloatBitness, Uncertain}, | 21 | primitive::{FloatBitness, Uncertain}, |
22 | utils::all_super_traits, | 22 | utils::all_super_traits, |
23 | Canonical, InEnvironment, TraitEnvironment, TraitRef, Ty, TypeCtor, TypeWalk, | 23 | ApplicationTy, Canonical, InEnvironment, TraitEnvironment, TraitRef, Ty, TypeCtor, TypeWalk, |
24 | }; | 24 | }; |
25 | 25 | ||
26 | /// This is used as a key for indexing impls. | 26 | /// This is used as a key for indexing impls. |
@@ -214,7 +214,7 @@ pub fn iterate_method_candidates<T>( | |||
214 | // the methods by autoderef order of *receiver types*, not *self | 214 | // the methods by autoderef order of *receiver types*, not *self |
215 | // types*. | 215 | // types*. |
216 | 216 | ||
217 | let deref_chain: Vec<_> = autoderef::autoderef(db, Some(krate), ty).collect(); | 217 | let deref_chain = autoderef_method_receiver(db, krate, ty); |
218 | for i in 0..deref_chain.len() { | 218 | for i in 0..deref_chain.len() { |
219 | if let Some(result) = iterate_method_candidates_with_autoref( | 219 | if let Some(result) = iterate_method_candidates_with_autoref( |
220 | &deref_chain[i..], | 220 | &deref_chain[i..], |
@@ -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>, |
@@ -548,3 +567,20 @@ fn generic_implements_goal( | |||
548 | let obligation = super::Obligation::Trait(trait_ref); | 567 | let obligation = super::Obligation::Trait(trait_ref); |
549 | Canonical { num_vars, value: InEnvironment::new(env, obligation) } | 568 | Canonical { num_vars, value: InEnvironment::new(env, obligation) } |
550 | } | 569 | } |
570 | |||
571 | fn autoderef_method_receiver( | ||
572 | db: &impl HirDatabase, | ||
573 | krate: CrateId, | ||
574 | ty: InEnvironment<Canonical<Ty>>, | ||
575 | ) -> Vec<Canonical<Ty>> { | ||
576 | let mut deref_chain: Vec<_> = autoderef::autoderef(db, Some(krate), ty).collect(); | ||
577 | // As a last step, we can do array unsizing (that's the only unsizing that rustc does for method receivers!) | ||
578 | if let Some(Ty::Apply(ApplicationTy { ctor: TypeCtor::Array, parameters })) = | ||
579 | deref_chain.last().map(|ty| &ty.value) | ||
580 | { | ||
581 | let num_vars = deref_chain.last().unwrap().num_vars; | ||
582 | let unsized_ty = Ty::apply(TypeCtor::Slice, parameters.clone()); | ||
583 | deref_chain.push(Canonical { value: unsized_ty, num_vars }) | ||
584 | } | ||
585 | deref_chain | ||
586 | } | ||
diff --git a/crates/ra_hir_ty/src/tests/method_resolution.rs b/crates/ra_hir_ty/src/tests/method_resolution.rs index 644d59e17..f9b394f05 100644 --- a/crates/ra_hir_ty/src/tests/method_resolution.rs +++ b/crates/ra_hir_ty/src/tests/method_resolution.rs | |||
@@ -839,6 +839,24 @@ fn test() { (&S).foo()<|>; } | |||
839 | } | 839 | } |
840 | 840 | ||
841 | #[test] | 841 | #[test] |
842 | fn method_resolution_unsize_array() { | ||
843 | let t = type_at( | ||
844 | r#" | ||
845 | //- /main.rs | ||
846 | #[lang = "slice"] | ||
847 | impl<T> [T] { | ||
848 | fn len(&self) -> usize { loop {} } | ||
849 | } | ||
850 | fn test() { | ||
851 | let a = [1, 2, 3]; | ||
852 | a.len()<|>; | ||
853 | } | ||
854 | "#, | ||
855 | ); | ||
856 | assert_eq!(t, "usize"); | ||
857 | } | ||
858 | |||
859 | #[test] | ||
842 | fn method_resolution_trait_from_prelude() { | 860 | fn method_resolution_trait_from_prelude() { |
843 | let (db, pos) = TestDB::with_position( | 861 | let (db, pos) = TestDB::with_position( |
844 | r#" | 862 | r#" |
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#" |