aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorEdwin Cheng <[email protected]>2019-12-19 04:45:07 +0000
committerEdwin Cheng <[email protected]>2019-12-19 04:45:07 +0000
commitdddee23f43a0e1939124a607ba534e69a810843a (patch)
tree02fd55e52fcd54b43f218303b9a9fc2fd7d623b0 /crates
parent242f0ae1d8e6766091a6050431c3d417a43a2a3e (diff)
Add std::ops::Index support for infering
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_hir_def/src/path.rs1
-rw-r--r--crates/ra_hir_expand/src/name.rs1
-rw-r--r--crates/ra_hir_ty/src/infer.rs22
-rw-r--r--crates/ra_hir_ty/src/infer/expr.rs12
-rw-r--r--crates/ra_hir_ty/src/tests/traits.rs32
5 files changed, 63 insertions, 5 deletions
diff --git a/crates/ra_hir_def/src/path.rs b/crates/ra_hir_def/src/path.rs
index 3b26e8337..9e37ac416 100644
--- a/crates/ra_hir_def/src/path.rs
+++ b/crates/ra_hir_def/src/path.rs
@@ -254,6 +254,7 @@ macro_rules! __known_path {
254 (std::ops::Try) => {}; 254 (std::ops::Try) => {};
255 (std::ops::Neg) => {}; 255 (std::ops::Neg) => {};
256 (std::ops::Not) => {}; 256 (std::ops::Not) => {};
257 (std::ops::Index) => {};
257 ($path:path) => { 258 ($path:path) => {
258 compile_error!("Please register your known path in the path module") 259 compile_error!("Please register your known path in the path module")
259 }; 260 };
diff --git a/crates/ra_hir_expand/src/name.rs b/crates/ra_hir_expand/src/name.rs
index 59d8214fd..fd02ffa4e 100644
--- a/crates/ra_hir_expand/src/name.rs
+++ b/crates/ra_hir_expand/src/name.rs
@@ -161,6 +161,7 @@ pub mod known {
161 Range, 161 Range,
162 Neg, 162 Neg,
163 Not, 163 Not,
164 Index,
164 // Builtin macros 165 // Builtin macros
165 file, 166 file,
166 column, 167 column,
diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs
index 98ba05fc2..14bfdde3d 100644
--- a/crates/ra_hir_ty/src/infer.rs
+++ b/crates/ra_hir_ty/src/infer.rs
@@ -363,14 +363,28 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
363 } 363 }
364 364
365 fn resolve_associated_type(&mut self, inner_ty: Ty, assoc_ty: Option<TypeAliasId>) -> Ty { 365 fn resolve_associated_type(&mut self, inner_ty: Ty, assoc_ty: Option<TypeAliasId>) -> Ty {
366 self.resolve_associated_type_with_params(inner_ty, assoc_ty, &[])
367 }
368
369 fn resolve_associated_type_with_params(
370 &mut self,
371 inner_ty: Ty,
372 assoc_ty: Option<TypeAliasId>,
373 params: &[Ty],
374 ) -> Ty {
366 match assoc_ty { 375 match assoc_ty {
367 Some(res_assoc_ty) => { 376 Some(res_assoc_ty) => {
368 let ty = self.table.new_type_var(); 377 let ty = self.table.new_type_var();
378 let mut builder = Substs::builder(1 + params.len()).push(inner_ty);
379 for ty in params {
380 builder = builder.push(ty.clone());
381 }
382
369 let projection = ProjectionPredicate { 383 let projection = ProjectionPredicate {
370 ty: ty.clone(), 384 ty: ty.clone(),
371 projection_ty: ProjectionTy { 385 projection_ty: ProjectionTy {
372 associated_ty: res_assoc_ty, 386 associated_ty: res_assoc_ty,
373 parameters: Substs::single(inner_ty), 387 parameters: builder.build(),
374 }, 388 },
375 }; 389 };
376 self.obligations.push(Obligation::Projection(projection)); 390 self.obligations.push(Obligation::Projection(projection));
@@ -517,6 +531,12 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
517 let struct_ = self.resolver.resolve_known_struct(self.db, &path)?; 531 let struct_ = self.resolver.resolve_known_struct(self.db, &path)?;
518 Some(struct_.into()) 532 Some(struct_.into())
519 } 533 }
534
535 fn resolve_ops_index_output(&self) -> Option<TypeAliasId> {
536 let path = path![std::ops::Index];
537 let trait_ = self.resolver.resolve_known_trait(self.db, &path)?;
538 self.db.trait_data(trait_).associated_type_by_name(&name![Output])
539 }
520} 540}
521 541
522/// The kinds of placeholders we need during type inference. There's separate 542/// The kinds of placeholders we need during type inference. There's separate
diff --git a/crates/ra_hir_ty/src/infer/expr.rs b/crates/ra_hir_ty/src/infer/expr.rs
index 924ad3e81..011c6c5c6 100644
--- a/crates/ra_hir_ty/src/infer/expr.rs
+++ b/crates/ra_hir_ty/src/infer/expr.rs
@@ -422,10 +422,14 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
422 } 422 }
423 } 423 }
424 Expr::Index { base, index } => { 424 Expr::Index { base, index } => {
425 let _base_ty = self.infer_expr_inner(*base, &Expectation::none()); 425 let base_ty = self.infer_expr_inner(*base, &Expectation::none());
426 let _index_ty = self.infer_expr(*index, &Expectation::none()); 426 let index_ty = self.infer_expr(*index, &Expectation::none());
427 // FIXME: use `std::ops::Index::Output` to figure out the real return type 427
428 Ty::Unknown 428 self.resolve_associated_type_with_params(
429 base_ty,
430 self.resolve_ops_index_output(),
431 &[index_ty],
432 )
429 } 433 }
430 Expr::Tuple { exprs } => { 434 Expr::Tuple { exprs } => {
431 let mut tys = match &expected.ty { 435 let mut tys = match &expected.ty {
diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs
index 802937cb0..2d92a5eec 100644
--- a/crates/ra_hir_ty/src/tests/traits.rs
+++ b/crates/ra_hir_ty/src/tests/traits.rs
@@ -427,6 +427,38 @@ fn indexing_arrays() {
427} 427}
428 428
429#[test] 429#[test]
430fn infer_ops_index() {
431 let (db, pos) = TestDB::with_position(
432 r#"
433//- /main.rs crate:main deps:std
434
435struct Bar;
436struct Foo;
437
438impl std::ops::Index<u32> for Bar {
439 type Output = Foo;
440}
441
442fn test() {
443 let a = Bar;
444 let b = a[1];
445 b<|>;
446}
447
448//- /std.rs crate:std
449
450#[prelude_import] use ops::*;
451mod ops {
452 pub trait Index<Idx> {
453 type Output;
454 }
455}
456"#,
457 );
458 assert_eq!("Foo", type_at_pos(&db, pos));
459}
460
461#[test]
430fn deref_trait() { 462fn deref_trait() {
431 let t = type_at( 463 let t = type_at(
432 r#" 464 r#"