aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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.rs40
-rw-r--r--crates/ra_hir_ty/src/tests/method_resolution.rs18
-rw-r--r--crates/ra_hir_ty/src/tests/traits.rs28
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};
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 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.
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>,
@@ -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
571fn 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]
842fn method_resolution_unsize_array() {
843 let t = type_at(
844 r#"
845//- /main.rs
846#[lang = "slice"]
847impl<T> [T] {
848 fn len(&self) -> usize { loop {} }
849}
850fn test() {
851 let a = [1, 2, 3];
852 a.len()<|>;
853}
854"#,
855 );
856 assert_eq!(t, "usize");
857}
858
859#[test]
842fn method_resolution_trait_from_prelude() { 860fn 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]
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#"