diff options
author | Florian Diebold <[email protected]> | 2020-04-10 21:05:46 +0100 |
---|---|---|
committer | Florian Diebold <[email protected]> | 2020-04-13 14:07:39 +0100 |
commit | db32a2e4211f9444ef4f10b633e400d27ed2662e (patch) | |
tree | 00095f637d1775f0cce68d7c0bd6a01bae63e5de /crates/ra_hir_ty/src | |
parent | c388130f5ffbcbe7d3131213a24d12d02f769b87 (diff) |
Implement inline associated type bounds
Like `Iterator<Item: SomeTrait>`.
This is an unstable feature, but it's used in the standard library e.g. in the
definition of Flatten, so we can't get away with not implementing it :)
Diffstat (limited to 'crates/ra_hir_ty/src')
-rw-r--r-- | crates/ra_hir_ty/src/lower.rs | 28 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/tests/traits.rs | 47 |
2 files changed, 69 insertions, 6 deletions
diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs index 6c7bbc448..21e7baf8b 100644 --- a/crates/ra_hir_ty/src/lower.rs +++ b/crates/ra_hir_ty/src/lower.rs | |||
@@ -8,6 +8,8 @@ | |||
8 | use std::iter; | 8 | use std::iter; |
9 | use std::sync::Arc; | 9 | use std::sync::Arc; |
10 | 10 | ||
11 | use smallvec::SmallVec; | ||
12 | |||
11 | use hir_def::{ | 13 | use hir_def::{ |
12 | adt::StructKind, | 14 | adt::StructKind, |
13 | builtin_type::BuiltinType, | 15 | builtin_type::BuiltinType, |
@@ -596,21 +598,35 @@ fn assoc_type_bindings_from_type_bound<'a>( | |||
596 | .into_iter() | 598 | .into_iter() |
597 | .flat_map(|segment| segment.args_and_bindings.into_iter()) | 599 | .flat_map(|segment| segment.args_and_bindings.into_iter()) |
598 | .flat_map(|args_and_bindings| args_and_bindings.bindings.iter()) | 600 | .flat_map(|args_and_bindings| args_and_bindings.bindings.iter()) |
599 | .map(move |(name, type_ref)| { | 601 | .flat_map(move |binding| { |
600 | let associated_ty = associated_type_by_name_including_super_traits( | 602 | let associated_ty = associated_type_by_name_including_super_traits( |
601 | ctx.db.upcast(), | 603 | ctx.db.upcast(), |
602 | trait_ref.trait_, | 604 | trait_ref.trait_, |
603 | &name, | 605 | &binding.name, |
604 | ); | 606 | ); |
605 | let associated_ty = match associated_ty { | 607 | let associated_ty = match associated_ty { |
606 | None => return GenericPredicate::Error, | 608 | None => return SmallVec::<[GenericPredicate; 1]>::new(), |
607 | Some(t) => t, | 609 | Some(t) => t, |
608 | }; | 610 | }; |
609 | let projection_ty = | 611 | let projection_ty = |
610 | ProjectionTy { associated_ty, parameters: trait_ref.substs.clone() }; | 612 | ProjectionTy { associated_ty, parameters: trait_ref.substs.clone() }; |
611 | let ty = Ty::from_hir(ctx, type_ref); | 613 | let mut preds = SmallVec::with_capacity( |
612 | let projection_predicate = ProjectionPredicate { projection_ty, ty }; | 614 | binding.type_ref.as_ref().map_or(0, |_| 1) + binding.bounds.len(), |
613 | GenericPredicate::Projection(projection_predicate) | 615 | ); |
616 | if let Some(type_ref) = &binding.type_ref { | ||
617 | let ty = Ty::from_hir(ctx, type_ref); | ||
618 | let projection_predicate = | ||
619 | ProjectionPredicate { projection_ty: projection_ty.clone(), ty }; | ||
620 | preds.push(GenericPredicate::Projection(projection_predicate)); | ||
621 | } | ||
622 | for bound in &binding.bounds { | ||
623 | preds.extend(GenericPredicate::from_type_bound( | ||
624 | ctx, | ||
625 | bound, | ||
626 | Ty::Projection(projection_ty.clone()), | ||
627 | )); | ||
628 | } | ||
629 | preds | ||
614 | }) | 630 | }) |
615 | } | 631 | } |
616 | 632 | ||
diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs index 22ae6ca90..53461bdbb 100644 --- a/crates/ra_hir_ty/src/tests/traits.rs +++ b/crates/ra_hir_ty/src/tests/traits.rs | |||
@@ -1924,6 +1924,53 @@ fn test<T, U>() where T: Trait<U::Item>, U: Trait<T::Item> { | |||
1924 | } | 1924 | } |
1925 | 1925 | ||
1926 | #[test] | 1926 | #[test] |
1927 | fn inline_assoc_type_bounds_1() { | ||
1928 | let t = type_at( | ||
1929 | r#" | ||
1930 | //- /main.rs | ||
1931 | trait Iterator { | ||
1932 | type Item; | ||
1933 | } | ||
1934 | trait OtherTrait<T> { | ||
1935 | fn foo(&self) -> T; | ||
1936 | } | ||
1937 | |||
1938 | // workaround for Chalk assoc type normalization problems | ||
1939 | pub struct S<T>; | ||
1940 | impl<T: Iterator> Iterator for S<T> { | ||
1941 | type Item = <T as Iterator>::Item; | ||
1942 | } | ||
1943 | |||
1944 | fn test<I: Iterator<Item: OtherTrait<u32>>>() { | ||
1945 | let x: <S<I> as Iterator>::Item; | ||
1946 | x.foo()<|>; | ||
1947 | } | ||
1948 | "#, | ||
1949 | ); | ||
1950 | assert_eq!(t, "u32"); | ||
1951 | } | ||
1952 | |||
1953 | #[test] | ||
1954 | fn inline_assoc_type_bounds_2() { | ||
1955 | let t = type_at( | ||
1956 | r#" | ||
1957 | //- /main.rs | ||
1958 | trait Iterator { | ||
1959 | type Item; | ||
1960 | } | ||
1961 | |||
1962 | fn test<I: Iterator<Item: Iterator<Item = u32>>>() { | ||
1963 | let x: <<I as Iterator>::Item as Iterator>::Item; | ||
1964 | x<|>; | ||
1965 | } | ||
1966 | "#, | ||
1967 | ); | ||
1968 | // assert_eq!(t, "u32"); | ||
1969 | // doesn't currently work, Chalk #234 | ||
1970 | assert_eq!(t, "{unknown}"); | ||
1971 | } | ||
1972 | |||
1973 | #[test] | ||
1927 | fn unify_impl_trait() { | 1974 | fn unify_impl_trait() { |
1928 | assert_snapshot!( | 1975 | assert_snapshot!( |
1929 | infer_with_mismatches(r#" | 1976 | infer_with_mismatches(r#" |