diff options
-rw-r--r-- | crates/ra_hir/src/ty/infer.rs | 62 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests.rs | 63 |
2 files changed, 117 insertions, 8 deletions
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index 651a78fe5..7ca1ff595 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs | |||
@@ -35,16 +35,17 @@ use crate::{ | |||
35 | expr::{Body, Expr, BindingAnnotation, Literal, ExprId, Pat, PatId, UnaryOp, BinaryOp, Statement, FieldPat,Array, self}, | 35 | expr::{Body, Expr, BindingAnnotation, Literal, ExprId, Pat, PatId, UnaryOp, BinaryOp, Statement, FieldPat,Array, self}, |
36 | generics::{GenericParams, HasGenericParams}, | 36 | generics::{GenericParams, HasGenericParams}, |
37 | path::{GenericArgs, GenericArg}, | 37 | path::{GenericArgs, GenericArg}, |
38 | ModuleDef, | ||
38 | adt::VariantDef, | 39 | adt::VariantDef, |
39 | resolve::{Resolver, Resolution}, | 40 | resolve::{Resolver, Resolution}, |
40 | nameres::Namespace, | 41 | nameres::Namespace, |
42 | ty::infer::diagnostics::InferenceDiagnostic, | ||
41 | diagnostics::DiagnosticSink, | 43 | diagnostics::DiagnosticSink, |
42 | }; | 44 | }; |
43 | use super::{ | 45 | use super::{ |
44 | Ty, TypableDef, Substs, primitive, op, ApplicationTy, TypeCtor, CallableDef, TraitRef, | 46 | Ty, TypableDef, Substs, primitive, op, ApplicationTy, TypeCtor, CallableDef, TraitRef, |
45 | traits::{ Solution, Obligation, Guidance}, | 47 | traits::{ Solution, Obligation, Guidance}, |
46 | }; | 48 | }; |
47 | use self::diagnostics::InferenceDiagnostic; | ||
48 | 49 | ||
49 | /// The entry point of type inference. | 50 | /// The entry point of type inference. |
50 | pub fn infer(db: &impl HirDatabase, def: DefWithBody) -> Arc<InferenceResult> { | 51 | pub fn infer(db: &impl HirDatabase, def: DefWithBody) -> Arc<InferenceResult> { |
@@ -459,18 +460,28 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
459 | if remaining_index.is_none() { def.take_values()? } else { def.take_types()? }; | 460 | if remaining_index.is_none() { def.take_values()? } else { def.take_types()? }; |
460 | 461 | ||
461 | let remaining_index = remaining_index.unwrap_or(path.segments.len()); | 462 | let remaining_index = remaining_index.unwrap_or(path.segments.len()); |
463 | let mut actual_def_ty: Option<Ty> = None; | ||
462 | 464 | ||
463 | // resolve intermediate segments | 465 | // resolve intermediate segments |
464 | for segment in &path.segments[remaining_index..] { | 466 | for (i, segment) in path.segments[remaining_index..].iter().enumerate() { |
465 | let ty = match resolved { | 467 | let ty = match resolved { |
466 | Resolution::Def(def) => { | 468 | Resolution::Def(def) => { |
467 | // FIXME resolve associated items from traits as well | 469 | // FIXME resolve associated items from traits as well |
468 | let typable: Option<TypableDef> = def.into(); | 470 | let typable: Option<TypableDef> = def.into(); |
469 | let typable = typable?; | 471 | let typable = typable?; |
470 | 472 | ||
471 | let substs = | 473 | let ty = self.db.type_for_def(typable, Namespace::Types); |
472 | Ty::substs_from_path_segment(self.db, &self.resolver, segment, typable); | 474 | |
473 | self.db.type_for_def(typable, Namespace::Types).subst(&substs) | 475 | // For example, this substs will take `Gen::*<u32>*::make` |
476 | assert!(remaining_index > 0); | ||
477 | let substs = Ty::substs_from_path_segment( | ||
478 | self.db, | ||
479 | &self.resolver, | ||
480 | &path.segments[remaining_index + i - 1], | ||
481 | typable, | ||
482 | ); | ||
483 | |||
484 | ty.subst(&substs) | ||
474 | } | 485 | } |
475 | Resolution::LocalBinding(_) => { | 486 | Resolution::LocalBinding(_) => { |
476 | // can't have a local binding in an associated item path | 487 | // can't have a local binding in an associated item path |
@@ -489,6 +500,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
489 | // Attempt to find an impl_item for the type which has a name matching | 500 | // Attempt to find an impl_item for the type which has a name matching |
490 | // the current segment | 501 | // the current segment |
491 | log::debug!("looking for path segment: {:?}", segment); | 502 | log::debug!("looking for path segment: {:?}", segment); |
503 | actual_def_ty = Some(ty.clone()); | ||
504 | |||
492 | let item: crate::ModuleDef = ty.iterate_impl_items(self.db, |item| { | 505 | let item: crate::ModuleDef = ty.iterate_impl_items(self.db, |item| { |
493 | let matching_def: Option<crate::ModuleDef> = match item { | 506 | let matching_def: Option<crate::ModuleDef> = match item { |
494 | crate::ImplItem::Method(func) => { | 507 | crate::ImplItem::Method(func) => { |
@@ -528,8 +541,13 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
528 | Resolution::Def(def) => { | 541 | Resolution::Def(def) => { |
529 | let typable: Option<TypableDef> = def.into(); | 542 | let typable: Option<TypableDef> = def.into(); |
530 | let typable = typable?; | 543 | let typable = typable?; |
544 | let mut ty = self.db.type_for_def(typable, Namespace::Values); | ||
545 | if let Some(sts) = self.find_self_types(&def, actual_def_ty) { | ||
546 | ty = ty.subst(&sts); | ||
547 | } | ||
548 | |||
531 | let substs = Ty::substs_from_path(self.db, &self.resolver, path, typable); | 549 | let substs = Ty::substs_from_path(self.db, &self.resolver, path, typable); |
532 | let ty = self.db.type_for_def(typable, Namespace::Values).subst(&substs); | 550 | let ty = ty.subst(&substs); |
533 | let ty = self.insert_type_vars(ty); | 551 | let ty = self.insert_type_vars(ty); |
534 | Some(ty) | 552 | Some(ty) |
535 | } | 553 | } |
@@ -549,6 +567,38 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
549 | } | 567 | } |
550 | } | 568 | } |
551 | 569 | ||
570 | fn find_self_types(&self, def: &ModuleDef, actual_def_ty: Option<Ty>) -> Option<Substs> { | ||
571 | let actual_def_ty = actual_def_ty?; | ||
572 | |||
573 | if let crate::ModuleDef::Function(func) = def { | ||
574 | // We only do the infer if parent has generic params | ||
575 | let gen = func.generic_params(self.db); | ||
576 | if gen.count_parent_params() == 0 { | ||
577 | return None; | ||
578 | } | ||
579 | |||
580 | let impl_block = func.impl_block(self.db)?.target_ty(self.db); | ||
581 | let impl_block_substs = impl_block.substs()?; | ||
582 | let actual_substs = actual_def_ty.substs()?; | ||
583 | |||
584 | let mut new_substs = vec![Ty::Unknown; gen.count_parent_params()]; | ||
585 | |||
586 | // The following code *link up* the function actual parma type | ||
587 | // and impl_block type param index | ||
588 | impl_block_substs.iter().zip(actual_substs.iter()).for_each(|(param, pty)| { | ||
589 | if let Ty::Param { idx, .. } = param { | ||
590 | if let Some(s) = new_substs.get_mut(*idx as usize) { | ||
591 | *s = pty.clone(); | ||
592 | } | ||
593 | } | ||
594 | }); | ||
595 | |||
596 | Some(Substs(new_substs.into())) | ||
597 | } else { | ||
598 | None | ||
599 | } | ||
600 | } | ||
601 | |||
552 | fn resolve_variant(&mut self, path: Option<&Path>) -> (Ty, Option<VariantDef>) { | 602 | fn resolve_variant(&mut self, path: Option<&Path>) -> (Ty, Option<VariantDef>) { |
553 | let path = match path { | 603 | let path = match path { |
554 | Some(path) => path, | 604 | Some(path) => path, |
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index 82c4aeddb..8d8a0eaaa 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs | |||
@@ -1427,6 +1427,65 @@ fn test() { | |||
1427 | } | 1427 | } |
1428 | 1428 | ||
1429 | #[test] | 1429 | #[test] |
1430 | fn infer_associated_method_generics_without_args() { | ||
1431 | assert_snapshot_matches!( | ||
1432 | infer(r#" | ||
1433 | struct Gen<T> { | ||
1434 | val: T | ||
1435 | } | ||
1436 | |||
1437 | impl<T> Gen<T> { | ||
1438 | pub fn make() -> Gen<T> { | ||
1439 | loop { } | ||
1440 | } | ||
1441 | } | ||
1442 | |||
1443 | fn test() { | ||
1444 | let a = Gen::<u32>::make(); | ||
1445 | } | ||
1446 | "#), | ||
1447 | @r###" | ||
1448 | [76; 100) '{ ... }': ! | ||
1449 | [86; 94) 'loop { }': ! | ||
1450 | [91; 94) '{ }': () | ||
1451 | [114; 149) '{ ...e(); }': () | ||
1452 | [124; 125) 'a': Gen<u32> | ||
1453 | [128; 144) 'Gen::<...::make': fn make<u32>() -> Gen<T> | ||
1454 | [128; 146) 'Gen::<...make()': Gen<u32>"### | ||
1455 | ); | ||
1456 | } | ||
1457 | |||
1458 | #[test] | ||
1459 | fn infer_associated_method_generics_2_type_params_without_args() { | ||
1460 | assert_snapshot_matches!( | ||
1461 | infer(r#" | ||
1462 | struct Gen<T, U> { | ||
1463 | val: T, | ||
1464 | val2: U, | ||
1465 | } | ||
1466 | |||
1467 | impl<T> Gen<u32, T> { | ||
1468 | pub fn make() -> Gen<u32,T> { | ||
1469 | loop { } | ||
1470 | } | ||
1471 | } | ||
1472 | |||
1473 | fn test() { | ||
1474 | let a = Gen::<u32, u64>::make(); | ||
1475 | } | ||
1476 | "#), | ||
1477 | @r###" | ||
1478 | [102; 126) '{ ... }': ! | ||
1479 | [112; 120) 'loop { }': ! | ||
1480 | [117; 120) '{ }': () | ||
1481 | [140; 180) '{ ...e(); }': () | ||
1482 | [150; 151) 'a': Gen<u32, u64> | ||
1483 | [154; 175) 'Gen::<...::make': fn make<u64>() -> Gen<u32, T> | ||
1484 | [154; 177) 'Gen::<...make()': Gen<u32, u64>"### | ||
1485 | ); | ||
1486 | } | ||
1487 | |||
1488 | #[test] | ||
1430 | fn infer_type_alias() { | 1489 | fn infer_type_alias() { |
1431 | assert_snapshot_matches!( | 1490 | assert_snapshot_matches!( |
1432 | infer(r#" | 1491 | infer(r#" |
@@ -1814,8 +1873,8 @@ pub fn main_loop() { | |||
1814 | @r###" | 1873 | @r###" |
1815 | [144; 146) '{}': () | 1874 | [144; 146) '{}': () |
1816 | [169; 198) '{ ...t(); }': () | 1875 | [169; 198) '{ ...t(); }': () |
1817 | [175; 193) 'FxHash...efault': fn default<{unknown}, {unknown}>() -> HashSet<T, H> | 1876 | [175; 193) 'FxHash...efault': fn default<{unknown}, FxHasher>() -> HashSet<T, H> |
1818 | [175; 195) 'FxHash...ault()': HashSet<{unknown}, {unknown}>"### | 1877 | [175; 195) 'FxHash...ault()': HashSet<{unknown}, FxHasher>"### |
1819 | ); | 1878 | ); |
1820 | } | 1879 | } |
1821 | 1880 | ||