From db32a2e4211f9444ef4f10b633e400d27ed2662e Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Fri, 10 Apr 2020 22:05:46 +0200 Subject: Implement inline associated type bounds Like `Iterator`. 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 :) --- crates/ra_hir_ty/src/lower.rs | 28 ++++++++++++++++----- crates/ra_hir_ty/src/tests/traits.rs | 47 ++++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 6 deletions(-) (limited to 'crates/ra_hir_ty/src') 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 @@ use std::iter; use std::sync::Arc; +use smallvec::SmallVec; + use hir_def::{ adt::StructKind, builtin_type::BuiltinType, @@ -596,21 +598,35 @@ fn assoc_type_bindings_from_type_bound<'a>( .into_iter() .flat_map(|segment| segment.args_and_bindings.into_iter()) .flat_map(|args_and_bindings| args_and_bindings.bindings.iter()) - .map(move |(name, type_ref)| { + .flat_map(move |binding| { let associated_ty = associated_type_by_name_including_super_traits( ctx.db.upcast(), trait_ref.trait_, - &name, + &binding.name, ); let associated_ty = match associated_ty { - None => return GenericPredicate::Error, + None => return SmallVec::<[GenericPredicate; 1]>::new(), Some(t) => t, }; let projection_ty = ProjectionTy { associated_ty, parameters: trait_ref.substs.clone() }; - let ty = Ty::from_hir(ctx, type_ref); - let projection_predicate = ProjectionPredicate { projection_ty, ty }; - GenericPredicate::Projection(projection_predicate) + let mut preds = SmallVec::with_capacity( + binding.type_ref.as_ref().map_or(0, |_| 1) + binding.bounds.len(), + ); + if let Some(type_ref) = &binding.type_ref { + let ty = Ty::from_hir(ctx, type_ref); + let projection_predicate = + ProjectionPredicate { projection_ty: projection_ty.clone(), ty }; + preds.push(GenericPredicate::Projection(projection_predicate)); + } + for bound in &binding.bounds { + preds.extend(GenericPredicate::from_type_bound( + ctx, + bound, + Ty::Projection(projection_ty.clone()), + )); + } + preds }) } 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 @@ -1923,6 +1923,53 @@ fn test() where T: Trait, U: Trait { assert_eq!(t, "{unknown}"); } +#[test] +fn inline_assoc_type_bounds_1() { + let t = type_at( + r#" +//- /main.rs +trait Iterator { + type Item; +} +trait OtherTrait { + fn foo(&self) -> T; +} + +// workaround for Chalk assoc type normalization problems +pub struct S; +impl Iterator for S { + type Item = ::Item; +} + +fn test>>() { + let x: as Iterator>::Item; + x.foo()<|>; +} +"#, + ); + assert_eq!(t, "u32"); +} + +#[test] +fn inline_assoc_type_bounds_2() { + let t = type_at( + r#" +//- /main.rs +trait Iterator { + type Item; +} + +fn test>>() { + let x: <::Item as Iterator>::Item; + x<|>; +} +"#, + ); + // assert_eq!(t, "u32"); + // doesn't currently work, Chalk #234 + assert_eq!(t, "{unknown}"); +} + #[test] fn unify_impl_trait() { assert_snapshot!( -- cgit v1.2.3