diff options
Diffstat (limited to 'crates/ra_hir_ty/src')
-rw-r--r-- | crates/ra_hir_ty/src/tests/traits.rs | 27 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/traits.rs | 7 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/traits/chalk.rs | 72 |
3 files changed, 99 insertions, 7 deletions
diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs index 22ae6ca90..af8c63d64 100644 --- a/crates/ra_hir_ty/src/tests/traits.rs +++ b/crates/ra_hir_ty/src/tests/traits.rs | |||
@@ -2023,6 +2023,33 @@ fn main() { | |||
2023 | } | 2023 | } |
2024 | 2024 | ||
2025 | #[test] | 2025 | #[test] |
2026 | fn associated_type_bound() { | ||
2027 | let t = type_at( | ||
2028 | r#" | ||
2029 | //- /main.rs | ||
2030 | pub trait Trait { | ||
2031 | type Item: OtherTrait<u32>; | ||
2032 | } | ||
2033 | pub trait OtherTrait<T> { | ||
2034 | fn foo(&self) -> T; | ||
2035 | } | ||
2036 | |||
2037 | // this is just a workaround for chalk#234 | ||
2038 | pub struct S<T>; | ||
2039 | impl<T: Trait> Trait for S<T> { | ||
2040 | type Item = <T as Trait>::Item; | ||
2041 | } | ||
2042 | |||
2043 | fn test<T: Trait>() { | ||
2044 | let y: <S<T> as Trait>::Item = no_matter; | ||
2045 | y.foo()<|>; | ||
2046 | } | ||
2047 | "#, | ||
2048 | ); | ||
2049 | assert_eq!(t, "u32"); | ||
2050 | } | ||
2051 | |||
2052 | #[test] | ||
2026 | fn dyn_trait_through_chalk() { | 2053 | fn dyn_trait_through_chalk() { |
2027 | let t = type_at( | 2054 | let t = type_at( |
2028 | r#" | 2055 | r#" |
diff --git a/crates/ra_hir_ty/src/traits.rs b/crates/ra_hir_ty/src/traits.rs index 43d8d1e80..44fbdb197 100644 --- a/crates/ra_hir_ty/src/traits.rs +++ b/crates/ra_hir_ty/src/traits.rs | |||
@@ -194,13 +194,16 @@ fn solve( | |||
194 | } | 194 | } |
195 | remaining > 0 | 195 | remaining > 0 |
196 | }; | 196 | }; |
197 | let mut solve = || solver.solve_limited(&context, goal, should_continue); | 197 | let mut solve = || { |
198 | let solution = solver.solve_limited(&context, goal, should_continue); | ||
199 | log::debug!("solve({:?}) => {:?}", goal, solution); | ||
200 | solution | ||
201 | }; | ||
198 | // don't set the TLS for Chalk unless Chalk debugging is active, to make | 202 | // don't set the TLS for Chalk unless Chalk debugging is active, to make |
199 | // extra sure we only use it for debugging | 203 | // extra sure we only use it for debugging |
200 | let solution = | 204 | let solution = |
201 | if is_chalk_debug() { chalk::tls::set_current_program(db, solve) } else { solve() }; | 205 | if is_chalk_debug() { chalk::tls::set_current_program(db, solve) } else { solve() }; |
202 | 206 | ||
203 | log::debug!("solve({:?}) => {:?}", goal, solution); | ||
204 | solution | 207 | solution |
205 | } | 208 | } |
206 | 209 | ||
diff --git a/crates/ra_hir_ty/src/traits/chalk.rs b/crates/ra_hir_ty/src/traits/chalk.rs index e05fea843..12ffa69a0 100644 --- a/crates/ra_hir_ty/src/traits/chalk.rs +++ b/crates/ra_hir_ty/src/traits/chalk.rs | |||
@@ -626,6 +626,55 @@ fn convert_where_clauses( | |||
626 | result | 626 | result |
627 | } | 627 | } |
628 | 628 | ||
629 | fn generic_predicate_to_inline_bound( | ||
630 | db: &dyn HirDatabase, | ||
631 | pred: &GenericPredicate, | ||
632 | self_ty: &Ty, | ||
633 | ) -> Option<chalk_rust_ir::InlineBound<Interner>> { | ||
634 | // An InlineBound is like a GenericPredicate, except the self type is left out. | ||
635 | // We don't have a special type for this, but Chalk does. | ||
636 | match pred { | ||
637 | GenericPredicate::Implemented(trait_ref) => { | ||
638 | if &trait_ref.substs[0] != self_ty { | ||
639 | // we can only convert predicates back to type bounds if they | ||
640 | // have the expected self type | ||
641 | return None; | ||
642 | } | ||
643 | let args_no_self = trait_ref.substs[1..] | ||
644 | .iter() | ||
645 | .map(|ty| ty.clone().to_chalk(db).cast(&Interner)) | ||
646 | .collect(); | ||
647 | let trait_bound = | ||
648 | chalk_rust_ir::TraitBound { trait_id: trait_ref.trait_.to_chalk(db), args_no_self }; | ||
649 | Some(chalk_rust_ir::InlineBound::TraitBound(trait_bound)) | ||
650 | } | ||
651 | GenericPredicate::Projection(proj) => { | ||
652 | if &proj.projection_ty.parameters[0] != self_ty { | ||
653 | return None; | ||
654 | } | ||
655 | let trait_ = match proj.projection_ty.associated_ty.lookup(db.upcast()).container { | ||
656 | AssocContainerId::TraitId(t) => t, | ||
657 | _ => panic!("associated type not in trait"), | ||
658 | }; | ||
659 | let args_no_self = proj.projection_ty.parameters[1..] | ||
660 | .iter() | ||
661 | .map(|ty| ty.clone().to_chalk(db).cast(&Interner)) | ||
662 | .collect(); | ||
663 | let alias_eq_bound = chalk_rust_ir::AliasEqBound { | ||
664 | value: proj.ty.clone().to_chalk(db), | ||
665 | trait_bound: chalk_rust_ir::TraitBound { | ||
666 | trait_id: trait_.to_chalk(db), | ||
667 | args_no_self, | ||
668 | }, | ||
669 | associated_ty_id: proj.projection_ty.associated_ty.to_chalk(db), | ||
670 | parameters: Vec::new(), // FIXME we don't support generic associated types yet | ||
671 | }; | ||
672 | Some(chalk_rust_ir::InlineBound::AliasEqBound(alias_eq_bound)) | ||
673 | } | ||
674 | GenericPredicate::Error => None, | ||
675 | } | ||
676 | } | ||
677 | |||
629 | impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> { | 678 | impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> { |
630 | fn associated_ty_data(&self, id: AssocTypeId) -> Arc<AssociatedTyDatum> { | 679 | fn associated_ty_data(&self, id: AssocTypeId) -> Arc<AssociatedTyDatum> { |
631 | self.db.associated_ty_data(id) | 680 | self.db.associated_ty_data(id) |
@@ -708,12 +757,25 @@ pub(crate) fn associated_ty_data_query( | |||
708 | AssocContainerId::TraitId(t) => t, | 757 | AssocContainerId::TraitId(t) => t, |
709 | _ => panic!("associated type not in trait"), | 758 | _ => panic!("associated type not in trait"), |
710 | }; | 759 | }; |
760 | |||
761 | // Lower bounds -- we could/should maybe move this to a separate query in `lower` | ||
762 | let type_alias_data = db.type_alias_data(type_alias); | ||
711 | let generic_params = generics(db.upcast(), type_alias.into()); | 763 | let generic_params = generics(db.upcast(), type_alias.into()); |
712 | let bound_data = chalk_rust_ir::AssociatedTyDatumBound { | 764 | let bound_vars = Substs::bound_vars(&generic_params); |
713 | // FIXME add bounds and where clauses | 765 | let resolver = hir_def::resolver::HasResolver::resolver(type_alias, db.upcast()); |
714 | bounds: vec![], | 766 | let ctx = crate::TyLoweringContext::new(db, &resolver) |
715 | where_clauses: vec![], | 767 | .with_type_param_mode(crate::lower::TypeParamLoweringMode::Variable); |
716 | }; | 768 | let self_ty = Ty::Bound(crate::BoundVar::new(crate::DebruijnIndex::INNERMOST, 0)); |
769 | let bounds = type_alias_data | ||
770 | .bounds | ||
771 | .iter() | ||
772 | .flat_map(|bound| GenericPredicate::from_type_bound(&ctx, bound, self_ty.clone())) | ||
773 | .filter_map(|pred| generic_predicate_to_inline_bound(db, &pred, &self_ty)) | ||
774 | .map(|bound| make_binders(bound.shifted_in(&Interner), 0)) | ||
775 | .collect(); | ||
776 | |||
777 | let where_clauses = convert_where_clauses(db, type_alias.into(), &bound_vars); | ||
778 | let bound_data = chalk_rust_ir::AssociatedTyDatumBound { bounds, where_clauses }; | ||
717 | let datum = AssociatedTyDatum { | 779 | let datum = AssociatedTyDatum { |
718 | trait_id: trait_.to_chalk(db), | 780 | trait_id: trait_.to_chalk(db), |
719 | id, | 781 | id, |